サーチ…


前書き

デフォルトでは、Cコンパイラは構造体をレイアウトして、各メンバーに、アライメントのないアクセス、DEC Alphaや一部のARM CPUなどのRISCマシンの問題に対するペナルティを課すことなく、高速アクセスが可能です。

CPUアーキテクチャーとコンパイラーによって、構造体は、その構成メンバーのサイズの合計よりも多くのメモリー領域を占有する可能性があります。コンパイラは、メンバー間または構造の最後にパディングを追加できますが、最初は追加しません。

パッキングはデフォルトのパディングをオーバーライドします。

備考

エリックレイモンドは、 C構造パッキングのロストアートに関する記事を読んでいます。

パッキング構造

デフォルトでは、構造体はC言語で埋められます。この動作を避けたい場合は、明示的に要求する必要があります。 GCCでは__attribute__((__packed__))です。 64ビットマシンでこの例を考えてみましょう。

struct foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

構造体は自動的に8-byte境界になるようにパディングされ、次のようになります。

struct foo {
    char *p;     /* 8 bytes */
    char c;      /* 1 byte  */

    char pad[7]; /* 7 bytes added by compiler */

    long x;      /* 8 bytes */
};

sizeof(struct foo)17代わりに24 sizeof(struct foo)ます。これは、64ビットコンパイラが各ステップで8バイトのワードでメモリから読み書きするために発生し、 char c;を書き込もうとすると明らかchar c;メモリ内の1バイトは完全な8バイト(すなわちワード)がフェッチされ、その最初のバイトのみを消費し、その7つの連続したバイトは空のままであり、構造体パディングのための読出しおよび書込み操作に対してアクセスできない。

構造パッキング

しかし、 packed属性を追加すると、コンパイラはパディングを追加しません。

struct __attribute__((__packed__)) foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

sizeof(struct foo)17を返します。

一般に、パック構造が使用されます:

  • スペースを節約する。
  • ネットワークの各ノードの各アーキテクチャのアラインメントに依存することなく、ネットワークを介して送信するようにデータ構造をフォーマットすること。

ARM Cortex-M0などの一部のプロセッサでは、アラインされていないメモリアクセスが許可されていないことを考慮しなければなりません。そのような場合、構造体パッキングは未定義の動作につながり、CPUをクラッシュさせる可能性があります。

構造体のパディング

このstructが定義され、32ビットコンパイラでコンパイルされたとします。

struct test_32 {
    int a;      // 4 byte
    short b;    // 2 byte
    int c;      // 4 byte    
} str_32;

このstructはメモリの10バイトしか占有しないと予想されるかもしれませんが、 sizeof(str_32)を出力すると12バイトが使用されます。

これは、高速アクセスのためにコンパイラが変数を整列させるために起こりました。一般的なパターンは、基本型がNバイト(Nは1,2,4,8,16などの2の累乗で、それ以上はそれほど大きくない場合)を占める場合、変数はNバイトの境界に整列する必要がありますNバイトの倍数)。

sizeof(int) == 4およびsizeof(short) == 2で示された構造の場合、一般的なレイアウトは次のようになります。

  • int a;オフセット0に格納されます。サイズ4。
  • short b;オフセット4に格納される。サイズ2。
  • オフセット6の名前のないパディング。サイズ2。
  • int c;オフセット8で格納される。サイズ4。

したがって、 struct test_32は12バイトのメモリを占有します。この例では、後続のパディングはありません。

コンパイラは、 struct test_32のメンバーが高速アクセスのために適切に配置されるように、4バイト境界から始まるstruct test_32変数が確実に格納されるようにします。 malloc()calloc()realloc()などのメモリ割り当て関数は、返されるポインタがどのデータ型でも十分に整列され、動的に割り当てられた構造体も正しく整列されるようにするために必要です。

32ビットモードでコンパイルすると、コンパイラがdouble場所に配置された64ビットIntel x86_64プロセッサ(Intel Core i7 - MacOS SierraまたはMac OS Xを実行しているMacなど)のような奇妙な状況に終わることがあります。 4バイトの境界。同じハードウェア上では、64ビット・モードでコンパイルすると、コンパイラーは8バイトの境界にdouble配置されます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow