C a是双精度的printf(“%d”,a);在IA32和IA32-64中的工作方式不同

C a是双精度的printf(“%d”,a);在IA32和IA32-64中的工作方式不同,c,memory,printf,ieee-754,stdio,C,Memory,Printf,Ieee 754,Stdio,为什么以下代码在IA-32和x86-64上的工作方式完全不同 #include <stdio.h> int main() { double a = 10; printf("a = %d\n", a); return 0; } #包括 int main(){ 双a=10; printf(“a=%d\n”,a); 返回0; } 在IA-32上,结果始终为0。 但是,在x86-64上,结果可以是介于MAX_INT和MIN_INT之间

为什么以下代码在IA-32和x86-64上的工作方式完全不同

#include    <stdio.h>
int main()  {
     double a   =   10;
     printf("a  =   %d\n",  a);
     return 0;
}
#包括
int main(){
双a=10;
printf(“a=%d\n”,a);
返回0;
}
在IA-32上,结果始终为0。
但是,在x86-64上,结果可以是介于MAX_INT和MIN_INT之间的任何值。

%d
实际上用于打印
INT
。历史上,
d
代表“十进制”,而
o
代表八进制,
x
代表十六进制

打印
double
时,应使用
%e
%f
%g


使用错误的格式说明符会导致任何情况发生,包括意外结果。

将与格式字符串中的格式说明符不匹配的参数传递给
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
值。

使用与格式字符串不匹配的参数调用
printf
是未定义的行为。这不是我的领域,但是在x86-64上,
double
int
参数会在不同的寄存器中传递——因此
a
会在一个位置传递到
printf()
,但在处理格式字符串
printf()时
在另一个包含垃圾的寄存器中查找
int
参数,因为它不用于传递参数。您可能需要提及类型
double
的正确格式:
%g“
%f”
%e”
。我知道打印双精度的正确格式。这是我老师问的问题,所以我觉得这背后有点神秘。谢谢@MartinGao当你提交申请时,别忘了把答案归功于这个网站assignment@RaymondChen实际上,这只是ppt中的一个例子,与我的作业无关。我只是想知道它背后的秘密。据说这是百度的采访问题。@M.M OK~,这是我第一次在x86案例中问StackOverflow问题,根据IEEE754,我知道为什么总是0。但是,我对x86-64中的参数传递知之甚少。我使用gdb查看asm代码,发现它通过%xmm0传递一个变量,所以我认为您是对的。同样效果的一个有趣结果是,有时您可以以错误的顺序传递整数和浮点参数,但仍然可以获得正常的行为。在我的系统上有64位,我在
printf(“%d,%f\n”,1234,10.7)之间得到相同的结果
printf(“%d,%f\n”,10.71234)
因为
1234
是第一个
int
(在格式字符串之后),而
10.7
是第一个
double
,无论传递的顺序如何。我在系统上得到了相同的结果。你完全解决了我的问题,并告诉我在这种未定义的行为中到底发生了什么~谢谢~