typedef struct{
double d_num;
char c;
int num;
}Node;
int main(){
Node n = {1.0000, 'a', 3};
printf("%d %c %d\n", n.d_num, n.c, n.num);
}
其中应解释为64位double的部分被解释为32位整型。运行以上会显示97 0, 怎么用存储结构来解释这种异常?
typedef struct{
double d_num;
char c;
int num;
}Node;
int main(){
Node n = {1.0000, 'a', 3};
printf("%d %c %d\n", n.d_num, n.c, n.num);
}
其中应解释为64位double的部分被解释为32位整型。运行以上会显示97 0, 怎么用存储结构来解释这种异常?
printf("%d %c %d\n", n.d_num, n.c, n.num);
首先观察应该更加细致一点,应该还有更多的东西你需要测试。
printf("%d\n%c\n%d\n", n.d_num, n.c, n.num);
下面进入正题:
首先我们看一下正常的情况,%lf %c %d
,printf()
函数是怎么运行的呢?它从右到做把%lf %c %d
压到栈里面去,然后就去结构体中取数据了[2]。现在栈顶是 %lf
, 那么取64位出来,就得到了d.d_num
, 然后取8位的d.c
,最后取32位的d.num
。(我这里没有考虑内存对齐的问题和各种细节)
然后我们来看 %d %c %d
,他取数据大小的顺序则是 32 8 32 ,ok,那么堆栈里的数据是
1.0000, 'a', 3
show_double(n.d_num);
show_char(n.c);
show_int(n.num);
// n.d_num: 0x000000000000f03f
// n.c : 0x61
// n.num : 0x03000000
我们看一下,32位全为0, 后面连续的8位也为0, man ascii '\0' => 0
,
剩下的显示的n.num
就是32位的0x61
了,也就是a,至于最后的n.num
,压根没动。
尝试把1.000改大一点,结果自然会变化。
参考:
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
你用的是 32 位系统。我们 gcc -S 看下它的汇编:
4(%esp)
,这是printf
的第一个参数。通过 gdb 可以看到其十六进制表示为0x00000000 0x3ff00000
。把它的前一个字作为一个整数,即「0」;%eax
的值是把40(%esp)
的低字节(第 6、7 行)弄过来的,即'a'
,也就是打印出来的「97」;printf
中%c
对应的那个'\0'
是怎么来的呢?它是那个浮点数的后一个字的最低字节。64 位系统上函数调用方式不一样。结果是
97, \3, 97
。其中第三个「97」是编译器以为那个寄存器printf
函数不会用所以残留的之前的值,因为它的第二个参数是浮点数,通过%xmm0
寄存器传递的,但是printf
认为没有浮点数所以不使用。不同参数所使用的寄存器没什么规律,如下: