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

我们知道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.a
o.b = eax
eax = o.b
o.c = eax
eax = o.c
o.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.a
edx=o.b
eax=o.c
o.a=8
o.b=ecx
o.c=edx
o.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.a
o.b = eax
eax = o.b
o.c = eax
eax = o.c
o.d = eax


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

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



原文地址:https://www.cnblogs.com/dyllove98/p/3214958.html