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 值。