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

时间:2013-09-30 20:03:11

标签: c++ c floating-point printf cout

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

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

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

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

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

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

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

9 个答案:

答案 0 :(得分:64)

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

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

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

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

答案 1 :(得分:37)

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

答案 2 :(得分:12)

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

这也是undefined behavior错误地指定printf的格式,这也说明了使用gcc -Wall构建警告很重要的原因我收到以下警告(看到它live 的):

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

C ++中 std::coutoperator<<int的重载,因此在这种情况下会调用它。 C++ draft standard部分27.7.3.1 类模板basic_ostream 中我们可以看到此超载以及其他许多内容需要我们找到以下运算符声明:

basic_ostream<charT,traits>& operator<<(int n);

为了完整起见,回到未定义的行为,7.19.6.1 printf部分{{1}}部分引用的fprintf函数格式字符串段 9 表示:

  

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

答案 3 :(得分:11)

表达式

18 / 4 + 18 % 4

评估为 int

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

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

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

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

答案 4 :(得分:8)

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

快速谷歌“MSVCRT R6002”说:

  

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

     

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

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

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

答案 5 :(得分:4)

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

根据您的目的,您可以:

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

和/或

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

#include <iostream>
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);

答案 6 :(得分:2)

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

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

获取int响应而不是浮点数。您将获得与<<所选运算符

相同的结果

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

否则,您可以明确使用

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

获得6.00000结果。

答案 7 :(得分:1)

让你的一个数字成为浮点值:

#include <stdio.h>
int main()
{

    printf("%.0f", 18/4.0+18%4);
    return 0;
} 

答案 8 :(得分:0)

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

#include <stdio.h>

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