为什么解释为双精度的整数呈现零?
Why does an integer interpreted as a double render zero?
printf("%f", 20);
导致输出 0.000000
,而不是 20.000000
。我猜这与 int 在内存中的表示方式以及 double 在内存中的表示方式有关。令我惊讶的是,无论我如何改变 20
,例如通过增大数字,输出仍然是 0.000000
。有人可以解释一下这背后的机制吗?
首先,这是undefined behavior。 %f
需要 float
/double
类型的参数。传递 int
会产生不兼容的类型,因此它会调用 UB。
引用 C11
,章节 §7.21.6.1,fprintf()
f
,F
A double
argument representing a floating-point number [...]
a float
也是允许的,因为默认参数提升规则,它将被提升为 double
,这是那里的预期类型,因此 double
或float
可以接受,但 int
.
不行
...仅此而已。 UB,嗯,UB。您不能尝试用产生 UB 的代码来证明任何事情。
就是说,如果启用了适当的警告级别,代码应该根本无法编译。但是,如果您选择编译代码并生成 binary/assembly 代码,您会看到针对不同平台生成的不同代码。 中解释了其中一种情况,考虑到 Linux/OS X 上的 x86_64 arch。
问题是您的编译器假设 20
是 int
。您的选择是要么声明一个 float
变量并在此处输入它,要么添加一个类型转换。
例如
printf("%f", (double)20);
很可能您正在 platform/ABI 上编译代码,其中即使对于可变参数函数,数据也被传递到寄存器中,特别是 integer/floating 点值的不同寄存器。 x86_64 Linux/OS X 的行为就是这样。
调用方有一个整数要传递,因此将其放入rsi
;另一方面,printf
需要一个浮点值,因此它尝试从 xmm0
读取它。无论您如何将整数参数更改为任何其他值 printf
都不会受到影响 - if 只会打印调用时留在 xmm0
中的任何内容。
您实际上可以通过将调用更改为:
来检查是否属于这种情况
printf("%f", 20, 123.45);
如果它像我描述的那样工作,你应该看到 123.45 被打印出来(这里的调用者将 123.45 放入 xmm0
,因为它是传递给函数的第一个浮点参数;printf
表现为之前,但这次在 xmm0
中找到另一个值)。
printf("%f", 20);
导致输出 0.000000
,而不是 20.000000
。我猜这与 int 在内存中的表示方式以及 double 在内存中的表示方式有关。令我惊讶的是,无论我如何改变 20
,例如通过增大数字,输出仍然是 0.000000
。有人可以解释一下这背后的机制吗?
首先,这是undefined behavior。 %f
需要 float
/double
类型的参数。传递 int
会产生不兼容的类型,因此它会调用 UB。
引用 C11
,章节 §7.21.6.1,fprintf()
f
,F
A
double
argument representing a floating-point number [...]
a float
也是允许的,因为默认参数提升规则,它将被提升为 double
,这是那里的预期类型,因此 double
或float
可以接受,但 int
.
...仅此而已。 UB,嗯,UB。您不能尝试用产生 UB 的代码来证明任何事情。
就是说,如果启用了适当的警告级别,代码应该根本无法编译。但是,如果您选择编译代码并生成 binary/assembly 代码,您会看到针对不同平台生成的不同代码。
问题是您的编译器假设 20
是 int
。您的选择是要么声明一个 float
变量并在此处输入它,要么添加一个类型转换。
例如
printf("%f", (double)20);
很可能您正在 platform/ABI 上编译代码,其中即使对于可变参数函数,数据也被传递到寄存器中,特别是 integer/floating 点值的不同寄存器。 x86_64 Linux/OS X 的行为就是这样。
调用方有一个整数要传递,因此将其放入rsi
;另一方面,printf
需要一个浮点值,因此它尝试从 xmm0
读取它。无论您如何将整数参数更改为任何其他值 printf
都不会受到影响 - if 只会打印调用时留在 xmm0
中的任何内容。
您实际上可以通过将调用更改为:
来检查是否属于这种情况printf("%f", 20, 123.45);
如果它像我描述的那样工作,你应该看到 123.45 被打印出来(这里的调用者将 123.45 放入 xmm0
,因为它是传递给函数的第一个浮点参数;printf
表现为之前,但这次在 xmm0
中找到另一个值)。