Printf of Double或int

问题描述 投票:0回答:3

大家好,

      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声明为double,所以我们必须在printf函数中使用%f。我的问题是:在内存深处,为什么我们打印一个0,因为我们输入了一个int(即使程序已经预留了一个内存为double)?

谢谢

c++ memory int printf double
3个回答
4
投票

2作为IEEE 754双重的二进制表示是0x4000000000000000,将double传递给printf,期望int可能导致转换为整数,并且只查看底部的4个字节,这些都是0,因此打印0

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


1
投票

你有未定义的行为。

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

可能发生的是将double加载到浮点寄存器上,而printf在堆栈上查找int值。

现在任何体面的编译器都应该在格式字符串与参数类型不匹配时给出警告。始终阅读这些警告!


0
投票

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

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

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,它可能在调试模式(或类似的东西)中将整数设置为零。

请注意,不保证未定义的行为。编译器可能会执行任何操作,包括删除有问题的行或执行完全意外的操作。对于给定的编译器,系统和优化级别,此答案的分析是正确的。它在生成的程序集中被观察到,但任何微小的更改(即使在代码中的其他函数中)也可能导致完全不同的行为。不要依赖未定义的行为。

© www.soinside.com 2019 - 2024. All rights reserved.