データ アライメント の表に示すように、ネイティブ データ型には適切に定義されたアライメント構造がありますが、ユーザー定義データ型についてはどうでしょうか。C++ コンパイラは、構造体またはクラス内のすべてのメンバー変数が正しくアライメントされるようにする必要もあります。このため、コンパイラはメンバー変数間に「パディング」バイトを挿入することがあります。また、コンパイラは最後のデータ メンバーの後にさらにパディングを追加して、ユーザー定義型の配列内の各要素がアライメントされるようにすることもあります。次のような例があるとします。
|
|
GCC コンパイラは、常に struct One
のインスタンスが、構造体のすべてのメンバーの最も厳密なアライメント要件 (この場合 int
) にアライメントされたアドレスから開始されると想定します。これは、実際にユーザー定義タイプのアライメント要件が計算される方法です。メモリがx86-64 アライメント (アライメント 2 の short int
とアライメント 4 の int
) にあるとすると、struct
One
の i
データ メンバーを適切にアライメントするために、コンパイラは s
と i
の間に 2 バイトの余分なパディングを挿入してアライメントを作成する必要があります (次の図を参照)。同様に、データ メンバー c
をアライメントするには、コンパイラが c
の後に 3 バイトを挿入する必要があります。
struct One
の場合、コンパイラは構造体の要素の配置に基づいて、合計サイズ 12 バイトを推論します。ただし、構造体の要素が並べ替えられた場合 (struct Two
を参照)、コンパイラはより小さいサイズ、8 バイトを推論できるようになります。
デフォルトでは、C/C++ コンパイラは宣言された順序で構造体のメンバーをレイアウトし、メンバー間または最後のメンバーの後にパディング バイトを挿入して、各メンバーが正しくアライメントされるようにします。ただし、GCC C/C++ コンパイラの __attribute__((packed))
言語拡張を使用すると、パディングを挿入せずに、構造体のメンバーのアライメントがずれないようにできます。たとえば、システムが通常、すべての int
オブジェクトに 4 バイトのアライメントを必要とする場合、__attribute__((packed))
を使用すると、int
構造体メンバーが奇数オフセットで割り当てられる可能性があります。
アライメントされていないメモリにアクセスすると、コンパイラが一度に複数のメモリ チャンクを読み出すのではなく、メモリ バイト単位でコードを読み込むことができるので、__attribute__((packed))
の使用は慎重に検討する必要があります。