在 IA32 和 IA32-64 中使用“%d”以不同方式打印双变量输出 [已关闭]

问题描述 投票:0回答:2

为什么以下代码在 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 之间的任何值。这背后的原因是什么?

c memory printf ieee-754 stdio
2个回答
2
投票

%d
实际上是用于打印
int
。从历史上看,
d
代表“十进制”,与
o
代表八进制和
x
代表十六进制形成对比。

对于打印

double
,您应该使用
%e
%f
%g

使用错误的格式说明符会导致未定义的行为,这意味着任何事情都可能发生,包括意外的结果。


1
投票

将与格式字符串中的格式说明符不匹配的参数传递给

printf()
是未定义的行为...并且在未定义的行为下,任何事情都可能发生,并且结果不一定从一个实例到另一个实例一致 - 所以应该避免。

至于为什么您会看到 x86(32 位)和 x86-64 之间的差异,很可能是因为每种情况下传递参数的方式不同。

在 x86 情况下,

printf()
的参数可能在堆栈上传递,在 4 字节边界上对齐——因此,当
printf()
处理
%d
说明符时,它会从堆栈,实际上是
int
的低 4 个字节。 由于
a
为 10,这些字节没有设置位,因此它们被解释为
a
值 0。

在 x86-64 情况下,

int

的参数都在寄存器中传递(尽管如果有足够的参数,有些参数会在堆栈上)...但是

printf()
参数与
double 相比在不同的寄存器中传递
参数(例如 %xmm0 而不是 %rsi)。 因此,当
int
尝试处理
printf()
参数以匹配
int
说明符时,它会从传入
%d
的不同寄存器中获取它,并使用寄存器中留下的任何垃圾值而不是
a
的低字节,并将其解释为一些垃圾
a
值。
    

© www.soinside.com 2019 - 2024. All rights reserved.