a 是双精度的,printf("%d", a);在 IA32 和 IA32-64 中的工作方式不同
a is a double, printf("%d", a); works differently in IA32 and IA32-64
为什么以下代码在 IA-32 和 x86-64 上的工作方式完全不同?
#include <stdio.h>
int main() {
double a = 10;
printf("a = %d\n", a);
return 0;
}
在 IA-32 上,结果始终为 0。
但是,在 x86-64 上,结果可以是 MAX_INT 和 MIN_INT 之间的任何值。
%d
实际上是用来打印int
的。历史上 d
代表 "decimal",与 o
代表八进制和 x
代表十六进制形成对比。
要打印 double
,您应该使用 %e
、%f
或 %g
。
使用错误的格式说明符会导致 undefined behaviour,这意味着任何事情都可能发生,包括意外结果。
将与格式字符串中的格式说明符不匹配的参数传递给 printf()
是未定义的行为...并且对于未定义的行为,任何事情都可能发生,结果不一定与一个一致实例到另一个 - 所以应该避免它。
至于为什么您会看到 x86(32 位)和 x86-64 之间的差异,这可能是因为在每种情况下传递参数的方式不同。
在 x86 的情况下,printf()
的参数很可能在堆栈上传递,在 4 字节边界上对齐——所以当 printf()
处理 %d
说明符时从栈中读取一个4字节的int
,实际上是a
的低4字节。由于 a
是 10,这些字节没有位设置,因此它们被解释为 int
值 0。
在 x86-64 的情况下,printf()
的参数都是在寄存器中传递的(尽管如果有足够的寄存器,有些参数会在堆栈上)...但是 double
参数在与 int
参数不同的寄存器中传递(例如 %xmm0 而不是 %rsi)。因此,当 printf()
尝试处理 int
参数以匹配 %d
说明符时,它从另一个寄存器中获取 a
传入的参数,并使用任何垃圾值留在寄存器中而不是 a
的低字节,并将其解释为一些垃圾 int
值。
为什么以下代码在 IA-32 和 x86-64 上的工作方式完全不同?
#include <stdio.h>
int main() {
double a = 10;
printf("a = %d\n", a);
return 0;
}
在 IA-32 上,结果始终为 0。 但是,在 x86-64 上,结果可以是 MAX_INT 和 MIN_INT 之间的任何值。
%d
实际上是用来打印int
的。历史上 d
代表 "decimal",与 o
代表八进制和 x
代表十六进制形成对比。
要打印 double
,您应该使用 %e
、%f
或 %g
。
使用错误的格式说明符会导致 undefined behaviour,这意味着任何事情都可能发生,包括意外结果。
将与格式字符串中的格式说明符不匹配的参数传递给 printf()
是未定义的行为...并且对于未定义的行为,任何事情都可能发生,结果不一定与一个一致实例到另一个 - 所以应该避免它。
至于为什么您会看到 x86(32 位)和 x86-64 之间的差异,这可能是因为在每种情况下传递参数的方式不同。
在 x86 的情况下,printf()
的参数很可能在堆栈上传递,在 4 字节边界上对齐——所以当 printf()
处理 %d
说明符时从栈中读取一个4字节的int
,实际上是a
的低4字节。由于 a
是 10,这些字节没有位设置,因此它们被解释为 int
值 0。
在 x86-64 的情况下,printf()
的参数都是在寄存器中传递的(尽管如果有足够的寄存器,有些参数会在堆栈上)...但是 double
参数在与 int
参数不同的寄存器中传递(例如 %xmm0 而不是 %rsi)。因此,当 printf()
尝试处理 int
参数以匹配 %d
说明符时,它从另一个寄存器中获取 a
传入的参数,并使用任何垃圾值留在寄存器中而不是 a
的低字节,并将其解释为一些垃圾 int
值。