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

本文探讨了C语言中结构体初始化时的一种现象,即使用{}初始化时,不同编译器(如VS2010和GCC)可能会产生不同的结果。在VS2010下,C和C++的初始化结果相同,而在GCC的C编译中则出现不同情况。通过反汇编代码分析,作者试图揭示这种差异的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们知道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要这样生成指令?



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值