構造体の sizeof が各メンバーの sizeof の合計と等しくないのはなぜですか?

これは、アラインメントの制約を満たすためにパディングが追加されたためです。データ構造のアライメントは、プログラムのパフォーマンスと正確性の両方に影響します:

  • ミスアライン アクセスはハード エラーの可能性があります (多くの場合、SIGBUS ).
  • ミスアライン アクセスはソフト エラーの可能性があります。
    • 適度なパフォーマンスの低下のために、ハードウェアで修正されています。
    • またはソフトウェアのエミュレーションによって修正され、パフォーマンスが大幅に低下します。
    • さらに、アトミック性やその他の並行性の保証が破られ、微妙なエラーが発生する可能性があります。

x86 プロセッサの一般的な設定を使用した例を次に示します (すべて 32 ビット モードと 64 ビット モードを使用):

struct X
{
    short s; /* 2 bytes */
             /* 2 padding bytes */
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 3 padding bytes */
};

struct Y
{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
    short s; /* 2 bytes */
};

struct Z
{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

メンバーをアラインメントで並べ替えることにより、構造体のサイズを最小限に抑えることができます (基本型では、サイズによる並べ替えで十分です) (構造体 Z のように) 上記の例では)

重要な注意:C と C++ の両方の標準では、構造体のアラインメントは実装定義であると述べられています。したがって、各コンパイラは異なる方法でデータを配置することを選択する場合があり、その結果、データ レイアウトが異なり、互換性がなくなります。このため、さまざまなコンパイラで使用されるライブラリを扱う場合、コンパイラがデータを整列する方法を理解することが重要です。一部のコンパイラには、コマンドライン設定および/または特別な #pragma があります ステートメントを使用して、構造の配置設定を変更します。


ここの C FAQ で説明されているように、パッキングとバイト アラインメント:


たとえば、構造体を GCC で特定のサイズにする場合は、__attribute__((packed)) を使用します。 .

Windows では、/Zp オプションを指定して cl.exe コンパイラを使用する場合、アラインメントを 1 バイトに設定できます。

通常、CPU は、プラットフォームやコンパイラにもよりますが、4 (または 8) の倍数のデータにアクセスする方が簡単です。

したがって、基本的には調整の問題です。

変更するには正当な理由が必要です。