C a是双精度的printf(“%d”,a);在IA32和IA32-64中的工作方式不同
为什么以下代码在IA-32和x86-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之间
#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
,无论传递的顺序如何。我在系统上得到了相同的结果。你完全解决了我的问题,并告诉我在这种未定义的行为中到底发生了什么~谢谢~