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

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

#include  int main() { printf("%.5f", 18/4+18%4); return 0; } 

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

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

  #include  using namespace std; int main() { cout << 18/4+18%4 << endl; return 0; } 

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

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

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

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

 warning: format '%.5f' expects type 'double', but argument 2 has type 'int' 

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

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

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

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

 warning: format '%f' expects argument of type 'double', but argument 2 has type 'int' 

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

 basic_ostream& operator<<(int n); 

为了完整起见,回到未定义的行为,第7.19.6.1节中的C99草案标准 printf的部分引用的fprintf函数返回格式字符串第9段说:

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

表达方式

 18 / 4 + 18 % 4 

评估为int

但是printf格式字符串“%。5f”需要加倍。

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

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

 #include  int main() { printf("%d", 18 / 4 + 18 % 4); return 0; } 

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

一个快速谷歌“MSVCRT R6002”说:

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

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

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

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

在C中,因为您在printf格式说明符中明确指定浮点(“%f”),所以它期望浮点参数。 但是你给它一个“int”参数,因此问题。

根据您的目的,您可以:

1)将您的(否则为整数 )表达式转换为float

和/或

2)在你的cout流中使用setprecision,就像你在C中使用“%.5f”一样:

 #include  using namespace std; int main() { float x = 18/4+18%4; std::cout << std::setprecision(5) << x << endl; return 0; } 

3)如果你想要整数,使用printf ("%d", 18/4+18%4);

如果你想要相同的行为(和响应),你最好编码

 printf("%d\n", 18/4 + 18%4); 

获取int响应而不是浮点响应。 您将获得与<< operator selected is相同的结果

ostream& std::operator<<(ostream&, const int);

否则,您可以明确使用

 printf("%.5f\n", (double)(18/4 + 18%4)); 

获得6.00000结果。

将您的一个数字设为浮点值:

 #include  int main() { printf("%.0f", 18/4.0+18%4); return 0; } 

一种可能的替代方法是,对文字(或表达式本身)进行类型转换:

 #include  int main(void) { printf("%.5f", (float)18/4+18%4); return 0; }