printf("%f", 20);
会产生输出0.000000
,而非20.000000
。我猜这与内存中如何表示int以及如何在内存中表示double有关。令我惊讶的是,无论我如何改变20
,例如通过使数字更大,输出仍为0.000000
。有人可以解释一下它的基本机制吗?
答案 0 :(得分:4)
首先,这是undefined behavior。 %f
期望参数类型为float
/ double
。传递int
会使类型不兼容,因此会调用UB。
引用C11
,章节§7.21.6.1, fprintf()
f
,F
表示浮点数[...]
的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)
问题是您的编译器假设20
是int
。您可以选择声明float
变量并在此处输入或添加类型转换。
<强> e.g。强>
printf("%f", (double)20);