为什么整数被解释为双渲染零?

时间:2017-07-11 12:29:46

标签: c int printf double format-specifiers

printf("%f", 20);会产生输出0.000000,而非20.000000。我猜这与内存中如何表示int以及如何在内存中表示double有关。令我惊讶的是,无论我如何改变20,例如通过使数字更大,输出仍为0.000000。有人可以解释一下它的基本机制吗?

3 个答案:

答案 0 :(得分:4)

首先,这是undefined behavior%f期望参数类型为float / double。传递int会使类型不兼容,因此会调用UB。

引用C11,章节§7.21.6.1, fprintf()

  

fF

     

表示浮点数[...]

double参数

由于默认参数提升规则,还允许float,它将被提升为double,这是预期的类型,因此double或{ {1}}可以接受,但不是float

......就是这样。 UB,是,UB。您不能尝试使用生成UB的代码来证明任何事情。

也就是说,启用适当的警告级别后,代码根本不应该编译。但是,如果您选择编译代码并生成二进制/汇编代码,则可以看到为不同平台生成的不同代码。考虑到Linux / OS X上的x86_64 arch,在the other answer by Matteo Italia中解释了其中一种情况。

答案 1 :(得分:4)

很可能你是在平台/ ABI上编译你的代码,即使varargs函数数据也被传递到寄存器,特别是整数/浮点值的不同寄存器。 Linux / OS X上的x86_64就是这样。

调用者有一个要传递的整数,所以它将它放入rsi;另一方面,printf需要浮点值,因此它会尝试从xmm0读取它。无论你如何将整数参数更改为任何其他值printf都不受影响 - 如果只是打印在调用时保留到xmm0的任何内容。

您可以通过将呼叫更改为:

来实际检查是否是这种情况
printf("%f", 20, 123.45);

如果它按照我的描述工作,你应该看到打印123.45(这里的调用者将123.45放入xmm0,因为它是传递给函数的第一个浮点参数; printf表现与以前一样,但这次在xmm0中找到另一个值。

答案 2 :(得分:0)

问题是您的编译器假设20int。您可以选择声明float变量并在此处输入或添加类型转换。

<强> e.g。

printf("%f", (double)20);