一个C/C++结构体初始化有趣的现象

来源:互联网 发布:java 文件夹复制 覆盖 编辑:程序博客网 时间:2024/05/16 11:44

我们知道C语言当中结构可以使用{}进行初始化,例如有结构体定义如下:

typedef struct type_t {int a;int b;int c;int d;}type_t;
我们可以使用下面的语句来初始化一个变量:

struct type_t o = { 1, 2, 3, 4 }


但是如果像下面这样来初始化,结果会是什么呢?

type_t o = { 8, o.a, o.b, o.c };


其结果是依赖于编译器的实现,笔者分别在VS2010和GCC下进行了测试,结果如下:

1. vs2010下C和C++的结果都是:

o.a = 8, o.b = 8, o.c = 8, o.d = 8

2. GCC的C编译运行结果:

o.a = 8 o.b = 0, o.c = 0, o.d = 4195296

3. GCC的C++编译运行结果:

o.a = 8, o.b = 8, o.c = 8, o.d = 8


为啥会这样呢?带着疑问,笔者又去看了一下反汇编的代码,VS2010的反汇编代码如下:

type_t o = { 8, o.a, o.b, o.c };004113A8  mov         dword ptr [ebp-18h],8  004113AF  mov         eax,dword ptr [ebp-18h]  004113B2  mov         dword ptr [ebp-14h],eax  004113B5  mov         eax,dword ptr [ebp-14h]  004113B8  mov         dword ptr [ebp-10h],eax  004113BB  mov         eax,dword ptr [ebp-10h]  004113BE  mov         dword ptr [ebp-0Ch],eax  

这段代码翻译过来的意思就是:

o.a = 8;eax = o.ao.b = eaxeax = o.bo.c = eaxeax = o.co.d = eax


gcc编译的反汇编代码:

=> 0x00000000004004cd <+9>:     mov    -0x20(%rbp),%ecx   0x00000000004004d0 <+12>:    mov    -0x1c(%rbp),%edx   0x00000000004004d3 <+15>:    mov    -0x18(%rbp),%eax   0x00000000004004d6 <+18>:    movl   $0x8,-0x20(%rbp)   0x00000000004004dd <+25>:    mov    %ecx,-0x1c(%rbp)   0x00000000004004e0 <+28>:    mov    %edx,-0x18(%rbp)   0x00000000004004e3 <+31>:    mov    %eax,-0x14(%rbp)

这段代码可翻译如下:

ecx=o.aedx=o.beax=o.co.a=8o.b=ecxo.c=edxo.d=eax


g++编译的反汇编代码:

=> 0x00000000004005ad <+9>:     movq   $0x0,-0x20(%rbp)   0x00000000004005b5 <+17>:    movq   $0x0,-0x18(%rbp)   0x00000000004005bd <+25>:    movl   $0x8,-0x20(%rbp)   0x00000000004005c4 <+32>:    mov    -0x20(%rbp),%eax   0x00000000004005c7 <+35>:    mov    %eax,-0x1c(%rbp)   0x00000000004005ca <+38>:    mov    -0x1c(%rbp),%eax   0x00000000004005cd <+41>:    mov    %eax,-0x18(%rbp)   0x00000000004005d0 <+44>:    mov    -0x18(%rbp),%eax   0x00000000004005d3 <+47>:    mov    %eax,-0x14(%rbp)
这段代码翻译如下:

将o变量清零o.a = 8;eax = o.ao.b = eaxeax = o.bo.c = eaxeax = o.co.d = eax

现在该完全清楚了,g++和vs2010生成的汇编指令基本一致,都是先将前一个成员初始化后再进行取值。而gcc则是先将o的成员变量值全部保存的寄存器中,然后逐一对o变量进行初始化。

但是所不明白的是为何gcc要这样生成指令?



原创粉丝点击