x86上のC構造体の典型的なアライメント
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2021/09/19 14:58 UTC 版)
「データ構造アライメント」の記事における「x86上のC構造体の典型的なアライメント」の解説
構造体のメンバは、メモリに順番に格納されるため、以下の構造体では、メンバData1は常にData2の前に、Data2は常にData3の前に配置される。 struct MyData{ short Data1; short Data2; short Data3;}; short型が2バイトのメモリに格納されている場合、上記の構造体の各メンバは2バイトでアラインされる。Data1はオフセット0、Data2はオフセット2、Data3はオフセット4になる。この構造体のサイズは6バイトになる。 構造体の各メンバの型は通常、デフォルトのアライメントを持つ。つまり、プログラマから別途要求されない限り、あらかじめ決められた境界にアラインされる。次の典型的なアライメントは、Microsoft (Visual C++)、Borland/CodeGear (C++ Builder)、Digital Mars (DMC)、GNU (GCC) で32ビットx86用にコンパイルする場合のものである。 char(1バイト) - 1バイトアライメント short (2バイト) - 2バイトアライメント int(4バイト) - 4バイトアライメント long(4バイト) - 4バイトアライメント float(4バイト) - 4バイトアライメント double(8バイト) - Windowsでは8バイトアライメント。Linuxでは4バイトアライメント(コンパイル時に-malign-doubleオプションをつけると8バイト) long long(8バイト) - 4バイトアライメント long double(C++ BuilderとDMCでは10バイト、Visual C++では8バイト、GCCでは12バイト) - C++ Builderでは8バイトアライメント、DMCでは2バイトアライメント、Visual C++では8バイトアライメント、GCCでは4バイトアライメント ポインタ(4バイト) - 4バイトアライメント LP64モデルの64ビットシステムは次の通りである。 long(8バイト) - 8バイトアライメント double(8バイト) - 8バイトアライメント long long(8バイト) - 8バイトアライメント long double(GCCでは16バイト) - GCCでは16バイトアライメント ポインタ(8バイト) - 8バイトアライメント 一部のデータ型は実装に依存する。 次に挙げる構造体は、様々な型のメンバを有しており、そのバイト数を単純に合計すると8バイトになる。 struct MixedData{ char Data1; short Data2; int Data3; char Data4;}; コンパイル後、構造体にはパディングバイトが追加され、各メンバの適切なアライメントが保証される。 struct MixedData /* After compilation in 32-bit x86 machine */{ char Data1; /* 1バイト */ char Padding1[1]; /* 次のshort型を2バイト境界にアラインするための1バイトのパディング。 構造体が始まるアドレスが偶数であると仮定。 */ short Data2; /* 2バイト */ int Data3; /* 4バイト - 最も大きな構造体メンバ */ char Data4; /* 1バイト */ char Padding2[3]; /* 構造体のサイズを12バイトにするための3バイトのパディング */}; 構造体のコンパイルされたサイズは12バイトになる。最後のメンバの後にもパディングバイトが追加されていることに留意されたい。この場合、構造体の合計サイズは、構造体メンバの最大のアライメントの倍数となる。上の例では、構造体を12バイトのサイズにパディングするために最後のメンバの後に3バイトが追加される。 struct FinalPad{ float x; char n[1];}; 上記の例では、sizeof演算子により算出される FinalPad 構造体のサイズ sizeof(FinalPad) は5ではなく8(floatのアライメントの倍数)になる。 struct FinalPadShort{ short s; char n[3];}; 上記の例では、FinalPadShort 構造体のサイズ sizeof(FinalPadShort) は5や8ではなく6(shortのアライメントの倍数)になる。 構造体メンバの順序を変更したり、構造体メンバのコンパイラのアライメントを変更(パッキング)して、必要なメモリを減らす(または既存の形式に準拠させる)ために、構造体のアライメントを変更することができる。前述の MixedData 構造体にこれを適用すると、次のようになる。 struct MixedData /* 並べ替え後 */{ char Data1; char Data4; /* 並べ替えられた */ short Data2; int Data3;}; これにより、構造体のコンパイル後のサイズが、メンバのバイト数を単純に合計したサイズである8バイトと一致するようになった。Padding1[1] は Data4 によって置き換えられ(従って排除され)、構造体は既にlong wordのサイズにアラインされているので、 Padding2[3] はもはや必要ではない。 MixedData 構造体を1バイト境界にアライメントさせる別の方法は、プリプロセッサに構造体メンバの所定のアライメントを破棄させ、これによりパディングバイトを挿入しないようにすることである。 C11およびC++11よりも前の規格では、構造体メンバのアライメントを定義する標準的な方法はないが、コンパイラの中には #pragma ディレクティブを使用してソースファイル内のパッキングを指定するものがある。次にその例を示す。 #pragma pack(push) /* 現在のアライメントをスタックにプッシュ */#pragma pack(1) /* 1バイト境界にアライメントを設定 */struct MyPackedData{ char Data1; long Data2; char Data3;};#pragma pack(pop) /* スタックから元のアライメントを復元 */ この構造体は、32ビットシステムで6バイトのコンパイルサイズを持つ。上記のディレクティブは、Microsoft、Borland、GNUなどのコンパイラで利用できる。 もう1つの例: struct MyPackedData{ char Data1; long Data2 __attribute__((packed)); char Data3;};
※この「x86上のC構造体の典型的なアライメント」の解説は、「データ構造アライメント」の解説の一部です。
「x86上のC構造体の典型的なアライメント」を含む「データ構造アライメント」の記事については、「データ構造アライメント」の概要を参照ください。
- x86上のC構造体の典型的なアライメントのページへのリンク