C/C++ 中结构体输出异常的原因(存储结构)



 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, 怎么用存储结构来解释这种异常?

c C++

nowten 11 years, 11 months ago

你用的是 32 位系统。我们 gcc -S 看下它的汇编:


 1      fld1
 2      fstpl   32(%esp)
 3      movb    $97, 40(%esp)
 4      movl    $3, 44(%esp)
 5      movl    44(%esp), %edx
 6      movzbl  40(%esp), %eax
 7      movsbl  %al, %eax
 8      fldl    32(%esp)
 9      movl    %edx, 16(%esp)
10      movl    %eax, 12(%esp)
11      fstpl   4(%esp)
12      movl    $.LC1, (%esp)
13      call    printf
14      movl    $0, %eax

  • 11 行,存入浮点数到地址 4(%esp) ,这是 printf 的第一个参数。通过 gdb 可以看到其十六进制表示为 0x00000000 0x3ff00000 。把它的前一个字作为一个整数,即「0」;
  • 10 行, %eax 的值是把 40(%esp) 的低字节(第 6、7 行)弄过来的,即 'a' ,也就是打印出来的「97」;
  • printf %c 对应的那个 '\0' 是怎么来的呢?它是那个浮点数的后一个字的最低字节。

64 位系统上函数调用方式不一样。结果是 97, \3, 97 。其中第三个「97」是编译器以为那个寄存器 printf 函数不会用所以残留的之前的值,因为它的第二个参数是浮点数,通过 %xmm0 寄存器传递的,但是 printf 认为没有浮点数所以不使用。不同参数所使用的寄存器没什么规律,如下:

The first 6 integer parameters in a function under Linux are passed in registers rdi , rsi, rdx, rex, r8 and r9

Nodoubt answered 11 years, 11 months ago

Your Answer