Double或int的Printf

时间:2019-02-12 14:47:33

标签: c++ memory int printf double

大家好,

      int main()
{
  int a = 2;
  double b=2;
  printf( "with the d   a = %d \n", a); // print 2
  printf( "with the d   a = %d \n", b); // **print 0  <== My interrogation?**
  printf( "with the f   a = %f", b); // print 2.000000 
  return 0;
}

我知道,由于我们将b声明为双精度型,因此必须在printf函数中使用%f。 我的问题是:在内存深处,为什么我们将0打印出来,因为我们在b中放入了一个int(即使程序已经为double保留了内存)?

谢谢

3 个答案:

答案 0 :(得分:4)

2作为IEEE 754的double形式的二进制表示形式为0x4000000000000000,将double传递给期望int的printf可能导致强制转换为整数,并且仅查看全部为0的底部4个字节,因此将打印0

所有这些都是未定义的行为,因此不应依赖于此,并且需要确保使用正确的格式字符串。如果您的格式字符串与参数不匹配,一些现代编译器甚至会发出警告。

答案 1 :(得分:1)

您的行为不确定。

您要C来查看您的double所占用的内存,并将其解释为int。

可能正在发生的事情是将do​​uble加载到浮点寄存器中,而printf在堆栈中寻找int值。

这几天,当格式字符串与参数类型不匹配时,任何不错的编译器都应向您发出警告。务必阅读这些警告!

答案 2 :(得分:0)

这是未定义的行为(UB),因为格式字符串和参数之间不匹配。话虽如此,并假设编译器没有进行一些非平凡的转换,那么在这种情况下,UB具有一些典型的行为。

要查看会发生什么,您必须检查系统上的调用约定。该程序最有可能在64位x86体系结构上运行,该体系结构根据X86 calling conventions传递参数。在Windows上,第一个浮点值通过与其他整数参数(RCX,RDX,R8,R9中的一个)不同的寄存器(XMM0)传递。这意味着:

printf( "with the d   a = %d \n", b); 

double b传递到一个位置,而"%d"从另一个位置读取。另请注意,相关的整数被认为是易失性的,并且可以通过更早调用printf来丢弃。这意味着通过寄存器传递到前一个printf的int(a = 2)被相同的printf破坏。实际上,“%d”使printf读取从printf的内部实现中遗留下来的垃圾值。

结果,在Linux和Mac上,使用clang和gcc时,我得到的是随机垃圾值,而不是零。我假设最初的问题是在Windows上引用Visual Studio,这可能会在调试模式(或类似方式)下将整数设置为零。

请注意,无法保证行为未定义。编译器可能会做任何事情,包括删除有问题的行,或者做完全出乎意料的事情。对于给定的编译器,系统和优化级别,此答案的分析是正确的。在生成的程序集中观察到此错误,但是任何细微的更改(甚至是代码中的其他功能)都可能导致完全不同的行为。永远不要依赖未定义的行为。