在MinGW上使用iostreams错误地打印长双

时间:2015-05-06 15:06:02

标签: c++ mingw iostream

考虑代码

#include <iostream>

int main() {
  std::cout << 4.2L;
}

MinGW上进行编译并在以下输出中运行结果:

> g++ test.cc
> a.exe
-7.89773e-278

它是否是MinGW中的错误,是否有修复或解决方法?

更新

this question中描述的printf存在类似问题:

#include <cstdio>

int main() {
  std::printf("%Lg", 4.2L); // prints -7.89773e-278
}

但是,printf的问题可以通过定义__USE_MINGW_ANSI_STDIO来解决,而这个问题可以解决,所以我认为它应该是一个单独的问题。

1 个答案:

答案 0 :(得分:1)

这是一个MinGW错误......这个陈述似乎有争议,实际情况是它是微软C / C ++运行时库的限制,MinGW就是依赖。作为开发人员,您有责任了解工具的局限性,例如本工具的限制,并在这些限制范围内工作。

您遇到的问题是由于Microsoft在MSVC中缺少long double数据类型的任何明显实现,因此I / O子系统中缺少对该数据类型的有效支持由MSVCRT.DLL提供; (并且,在您告诉我之前,也许是愤怒的,当然,MSVC支持long double&#34;,我知道它语法,但语义< / em>它没有明确的实现,只是通过有效地忽略long限定符来表现,使long double成为裸double的同义词。

相反,GCC和MinGW 确实的实现为long double,与double不同;前者是80位实体,而后者是64位,并且是MSVC的两种数据类型的64位实现的精确模拟。当您需要80位浮点计算的更高精度时,这很好,但是当涉及到输出结果时,它可能会导致问题,例如您遇到的问题; (I / O转换器是一个long double数据实体的80位原始数据表示,它需要64位;内部表示不相同,所以当尾数的一部分被解释为指数)。

正如您已经注意到的那样,虽然MSVCRT.DLL仅支持64位double值的输出,但MinGW确实提供了C&#39 printf样式I / O的替代实现,可以正确翻译80位格式;但是,这并没有扩展到支持C ++样式的I / O.因此,在C ++代码中,您不能简单地利用MinGW替代I / O实现,同时继续使用C ++ I / O语义;您必须识别MSVCRT.DLL限制,并相应地编写应用程序代码。您可以考虑的一些选项包括: -

  1. 放弃使用long double数据类型,并按double执行计算; (这是 only 选项,有效选项可供Microsoft编译器的用户使用,因为它并不真正具有独特的long double数据类型实现开始)。
  2. long double执行计算,但将结果转换为double以进行输出。
  3. 使用C样式I / O函数代替C ++ I / O语义,并通过使用printf-posix中的任何一个进行编译来启用MinGW的替代-D_GNU_SOURCE实现, -D_BSD_SOURCE-D_XOPEN_SOURCE=700-D_POSIX_C_SOURCE=200809L,或者更好的是,将#define添加到您的来源中的任何一个,之前 {{ 1}})。如果愿意,您也可以替换#include_XOPEN_SOURCE的任何早期合规级别; (但是,请忽略一些评论员提供的令人难以置信的错误建议,以_POSIX_C_SOURCE进行编译;引入该宏名称的双下划线将其标记为&#34 ;实现保留&#34;,因此,作为编译器实现的最终用户,您不应该直接引用它。
  4. 使用C&#39; -D__USE_MINGW_ANSI_STDIO函数将snprintf数据转换为C字符串表示,然后使用C ++语义输出,而不是让C ++转换{{1的原始形式实体直接。 (IIRC,Microsoft不提供long double - 他们提供long double - 所以如果您小心使用ANSI函数名称,您将获得80位snprintf支持自动地)。