一つのC/C++構造体が面白い現象を初期化する

2911 ワード

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 };

 
その結果,コンパイラの実装に依存し,筆者はVS 2010とGCCのそれぞれでテストを行った結果,以下のようになった.
1.vs 2010の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
どうしてこんなことになったの?疑問を持って、筆者はまた逆アセンブリのコードを見に行きました.VS 2010の逆アセンブリコードは以下の通りです.
 
	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++とvs 2010で生成されたアセンブリ命令はほぼ一致し、前のメンバーを初期化してから値を取ることが明らかになった.gccは,まずoのメンバ変数値をすべて格納したレジスタにおいて,o変数を1つずつ初期化する.
 
しかし、なぜgccがこのように命令を生成するのか分からない.