一つのC/C++構造体が面白い現象を初期化する
2911 ワード
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の逆アセンブリコードは以下の通りです.
このコードを翻訳すると、
gccコンパイルの逆アセンブリコード:
このコードは次のように翻訳できます.
g++コンパイルの逆アセンブリコード:
このコードは次のように翻訳されています.
g++とvs 2010で生成されたアセンブリ命令はほぼ一致し、前のメンバーを初期化してから値を取ることが明らかになった.gccは,まずoのメンバ変数値をすべて格納したレジスタにおいて,o変数を1つずつ初期化する.
しかし、なぜgccがこのように命令を生成するのか分からない.
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がこのように命令を生成するのか分からない.