5

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

ビットフィールドの概念を理解しようとしていました。しかし、CASE III の次の構造体のサイズが 8 バイトになる理由がわかりません。

ケース I:

struct B    
{
    unsigned char c;  // +8 bits
} b;

sizeof(b); // 出力: 1 (私のシステムでは unsigned char が 1 バイトを占めるため)

ケース II:

struct B
{
    unsigned b: 1;
} b;

 sizeof(b); // Output: 4 (because unsigned takes 4 bytes on my system)

ケース III:

struct B
{
    unsigned char c;  // +8 bits
    unsigned b: 1;    // +1 bit
} b;

sizeof(b); // Output: 8 

ケース III の出力が 8 になる理由がわかりません。1(char) + 4(unsigned) = 5 と予想していました。

4

6 に答える 6

7

を使用して構造体のレイアウトを確認できますが、offsetof次のようなものになります。

struct B
{
    unsigned char c;  // +8 bits
    unsigned char pad[3]; //padding
    unsigned int bint; //your b:1 will be the first byte of this one
} b;

さて、(32 ビット アーキテクチャでは) が であることは明らかsizeof(b)です8よね。

問題は、なぜ 3 バイトのパディングで、多かれ少なかれなのかということです。

答えは、構造体へのフィールドのオフセットには、フィールド自体の型と同じアライメント要件があるということです。お使いのアーキテクチャでは、整数は 4 バイトでアラインされているためoffsetof(b, bint)、4 の倍数でなければなりません。c前があるため、0 にすることはできません。したがって、4 になります。フィールドbintがオフセット 4 から始まり、4 バイトの長さの場合、構造体のサイズは 8 です。

それを見る別の方法は、構造体のアラインメント要件がそのフィールドの中で最大であるため、これBは 4 バイト アラインされます (ビット フィールドであるため)。ただし、型のサイズはアライメントの倍数でなければならず、4 では不十分なので 8 になります。

于 2012-10-06T18:19:02.377 に答える
3

ここでアライメント効果が見られると思います。

多くのアーキテクチャでは、ワード サイズの倍数であるメモリ内のアドレスに整数を格納する必要があります。

これが、3 番目の構造体の char がさらに 3 バイトでパディングされ、次の符号なし整数がワード サイズの倍数であるアドレスから始まる理由です。

于 2012-10-06T17:23:23.157 に答える
2

Char は定義上、1 バイトです。int は、32 ビット システムでは 4 バイトです。そして、構造体には余分な 4 が埋め込まれています。

パディングの説明については、http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86を参照してください。

于 2012-10-06T17:20:23.047 に答える
1

メモリへのアクセスを揃えるために、構造体をパックする場合、コンパイラはパディングを追加します。パディングは追加されません。

于 2012-10-06T17:22:58.643 に答える
1

構造体のアラインメントと合計サイズは、プラットフォームとコンパイラ固有です。ここでは、率直で予測可能な答えを期待することはできません。コンパイラは、常に何らかの特別なアイデアを持つことができます。例えば:

struct B
{
    unsigned b0: 1;    // +1 bit
    unsigned char c;  // +8 bits
    unsigned b1: 1;    // +1 bit
};

コンパイラは、フィールド b0 と b1 を 1 つの整数にマージできますが、できない場合があります。それはコンパイラ次第です。一部のコンパイラには、これを制御するコマンド ライン キーがありますが、一部のコンパイラにはありません。その他の例:

struct B
{
    unsigned short c, d, e;
};

この構造体のフィールドをパックするかしないかは、コンパイラ次第です (32 ビット プラットフォームを想定)。構造体のレイアウトは、DEBUG ビルドと RELEASE ビルドで異なる場合があります。

次のパターンのみを使用することをお勧めします。

struct B
{
    unsigned b0: 1;
    unsigned b1: 7;
    unsigned b2: 2;
};

同じ型を共有する一連のビット フィールドがある場合、コンパイラはそれらを 1 つの int に配置します。そうしないと、さまざまな側面が発生する可能性があります。また、大規模なプロジェクトでは、コードの一部を記述し、他の誰かが makefile を記述および書き換えることを考慮してください。コードをある dll から別の dll に移動します。この時点で、コンパイラ フラグが設定および変更されます。99% の確率で、それらの人々はあなたの構造体のアラインメント要件をまったく知らないでしょう。彼らはあなたのファイルを開くことさえしません。

于 2012-10-06T17:56:05.690 に答える
1

私はこれをもう一度見て、これが私が見つけたものです。

  1. C book から、「フィールドに関するほとんどすべてが実装依存です。」
  2. 私のマシンで:
 struct B {
    unsigned c: 8;
    unsigned b: 1;
}b;
printf("%lu\n", sizeof(b));

ショートである4を印刷します。

ビットフィールドと通常の構造体要素を混在させていました。

ところで、ビット フィールドは次のように定義されます。それはビットフィールドの精神ではないように思われます(もうビットではないため)

于 2012-10-06T17:59:44.167 に答える