データ構造アライメント
一部のMicrosoftコンパイラ、特にRISCプロセッサでは、プロジェクトのデフォルトパッキング(/Zp ディレクティブ)と #pragma pack ディレクティブの間に予期しない関係がある。#pragma pack ディレクティブは、プロジェクトのデフォルトパッキングから構造体のパッキングサイズを減らすためにのみ使用できる。これはライブラリヘッダーとの相互運用性の問題を引き起こすケースがある(例えばヘッダーで #pragma pack(8) を使用し、プロジェクトのパッキングがこれよりも小さい場合)。このため、プロジェクトパッキングをデフォルトの8バイト以外の値に設定すると、ライブラリヘッダーで使用される #pragma pack ディレクティブが破棄され、構造間のバイナリの非互換性が発生する。x86用にコンパイルする場合は、この制限はない。
メモリアドレス a は、a が n バイトの倍数(n は2の累乗)であるときに、「n バイトアライメント」と呼ばれる。この場合、バイトはメモリアクセスの最小単位である。つまり、各メモリアドレスは異なるバイトを指定する。二進数で表現した場合、n バイトアライメントされたアドレスの下位の桁は、最小で log2(n) 桁がゼロになる。
「b ビットアライメント」は、「b/8 バイトアライメント」とも表現できる(例えば、64ビットアライメントは8バイトアライメント)。
アクセスされるデータが n バイト長であり、データアドレスが n バイトアライメントされている場合、メモリアクセスは「アラインされている」(aligned) という。メモリアクセスがアライメントされていない場合は、「アラインされていない」(misaligned) という。定義上、バイトメモリアクセスは常にアラインされている。
n バイト長のプリミティブ・データを参照するメモリポインタは、nバイトアライメントされたアドレスのみを含むことが許可されていれば、「アラインされている」という。データ集合体(構造体または配列)を参照するメモリポインタは、集合体内の各プリミティブデータがアラインされている場合かつその場合にのみ、アラインされている。
上記の定義は、各プリミティブデータが2の累乗バイトの長さであると仮定している。これが当てはまらない場合(x86の80ビット浮動小数点の場合など)、コンテキストはデータがアラインされているとみなされる条件に影響する。
構造体は、スタックに静的なサイズで、またはヒープ上に動的なサイズで格納できる。
コンパイラ(またはインタプリタ)は、通常、アラインされた境界上に個々のデータ項目を割り当てるが、データ構造はしばしば異なるアライメント要件を有するメンバーを有する。適切なアライメントを維持するために、トランスレータは通常、追加の無名のデータメンバーを挿入して、各メンバーが適切にアライメントされるようにする。さらに、データ構造全体には、終端に名前のないメンバーが埋め込まれている場合がある。これにより、構造体配列の各メンバを適切にアラインすることができる。
パディングは、構造体のメンバの後に大きなアライメントが必要なメンバがある場合、または構造体の最後に挿入された場合にのみ挿入される。 構造体内のメンバの順序を変更することで、アライメントを維持するのに必要なパディングの量を変更することができる。例えば、アライメント要件の小さい順にメンバがソートされている場合、パディングは最小限で済む。必要なパディングの最小量は、常に構造体内の最大のアライメントよりも小さくなる。必要とされるパディングの最大量の計算は、より複雑だが、全てのメンバのアラインメント必要量から、構造体メンバの最小アライメントされた半分のアライメント必要量の合計の2倍を引いた値よりも小さい。