为什么printf中相同表达式的输出与cout不同?

Gov*_*mar 26 c c++ floating-point printf cout

我正在使用Visual C++ 2012并从命令行编译以下文件:

#include <stdio.h>
int main()
{
    printf("%.5f", 18/4+18%4);
    return 0;
} 
Run Code Online (Sandbox Code Playgroud)

链接MSVCRT.LIB而不是LIBCMT以避免运行时错误R6002.
对于此程序,输出的值为0.00000.

但是,如果我在C++中执行完全相同的操作

 #include <iostream>
 using namespace std;
 int main()
 {
      cout << 18/4+18%4 << endl;
      return 0;
 }
Run Code Online (Sandbox Code Playgroud)

现在,它打印出6,就像它应该的那样.

有什么不同?它与语言本身(C vs C++)或输出方法(cout vs printf)有关,还是只是与MSVC的怪癖?

Esc*_*alo 64

表达式18/4+18%4求值为a int,并且您正在请求浮点数.你应该总是在启用警告的情况下进行编译,并注意它们(他们说警告是等待发生的错误,并且它们是正确的).

这就是我的编译器(GCC 4.8.1)告诉我的(甚至没有强制执行-Wall):

warning: format ‘%.5f’ expects type ‘double’, but argument 2 has type ‘int’
Run Code Online (Sandbox Code Playgroud)

另一方面,该std::cout<<操作能够推断出表达式的类型并将其正确地流式传输到屏幕上.

  • `%.5f`格式需要`double`,而不是`float`.(`printf`的`float`参数被提升为`double`但在这种情况下不相关.) (8认同)

Gab*_*abe 37

C函数正在传递一个整数,但是你告诉它(with %f)期望一个双精度浮点数,所以它失败了.C++函数知道它正在传递一个整数,因此它可以正常工作.

  • C11dr 7.21.6.1 9"如果任何参数不是相应转换规范的正确类型,则行为未定义." (11认同)
  • @chux:的确,"kaboom"实际上是允许的结果之一!:) (4认同)
  • @DavidHammen:它确实无法正常工作*,但仅仅因为它为他打印0并不意味着它会为每个人打印0.对于一些人来说,它可以去kaboom. (2认同)

Sha*_*our 12

Ç示例此表达式18/4+18%4将评估为一个INT由于所有操作数都是整数常量但要指定这是一个printf,因此它是将被错误地处理.另一方面,如果您在表达式的除法部分中使用了浮点常量,例如18.0/4+18%4整个表达式将计算为double.或者,您也可以使用"%d"格式说明符.

这也是错误地指定格式的未定义行为printf,这也说明了为什么构建警告很重要,使用gcc -Wall我收到以下警告(请参见实时):

warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ 
Run Code Online (Sandbox Code Playgroud)

C++中, std :: coutoperator <<有一个重载int,因此在这种情况下会被调用.我们可以看到这个重载是C++草案标准所要求的许多其他重载,在27.7.3.1 类模板basic_ostream中我们找到以下运算符声明:

basic_ostream<charT,traits>& operator<<(int n);
Run Code Online (Sandbox Code Playgroud)

为了完整起见,盘旋回未定义的行为,在C99标准草案中部分7.19.6.1 fprintf函数其中printf的部分是指回到格式字符串的第9说:

如果转换规范无效,则行为未定义.[...]


vil*_*lla 11

表达方式

18 / 4 + 18 % 4
Run Code Online (Sandbox Code Playgroud)

评估为int.

printf格式字符串"%.5f"需要加倍.

使用c ++和ostreams,语言可以自动确定输出类型.

只需将您的C代码更改为以下内容:

#include <stdio.h>
int main()
{
    printf("%d", 18 / 4 + 18 % 4);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Dre*_*all 8

其他人已正确指出printf()语句中的int/double不匹配.我只想评论你的声明,"链接MSVCRT.LIB而不是LIBCMT,以避免运行时错误R6002." 这个简单的程序不应该对运行时环境造成过度负担,因此像这样的运行时错误应该是代码中未定义行为的红色标志.

一个快速的谷歌"MSVCRT R6002"说:

C运行时错误R6002 浮点支持未加载

必要的浮点库没有链接.通过检查以下可能的原因来解决问题

  1. 该程序是编译或链接的选项,如/ FPi87,需要一个协处理器,但该程序是在没有安装协处理器的机器上运行的.
  2. printf_s或scanf_s函数的格式字符串包含浮点格式规范,程序不包含任何浮点值或变量.
  3. 编译器通过仅在必要时加载浮点支持来最小化程序的大小.编译器无法检测格式字符串中的浮点格式规范,因此它不会加载必要的浮点例程.
  4. 使用浮点参数对应浮点格式规范,或在程序中的其他位置执行浮点赋值.这会导致加载浮点支持.
  5. 在混合语言程序中,在链接程序时,在FORTRAN库之前指定了C库.最后重新链接并指定C库.

当然,这里的教训是你应该密切关注编译器和运行时警告和错误.如有疑问,请始终假设问题出在您的代码中,而不是编译器中.