4

次のコードがメモリにどのように配置されるかについて、私は少し戸惑っています。

struct Thing
{
    union
    {
        unsigned value:24;
        uint8_t bytes[3];
    };
    Thing(int v)
            :value(v)
    {}

    void foo()
    {
        printf("Thing %p value=%d !\n", this, value);
    }

} __attribute__((__packed__));

Linux 上の gcc 3.3、4.3、または 4.6 (考えられる特別なオプションなし - 4.6 では "-Wall -g" のみ) では、構造体のサイズは常に 4 です。

$ pahole ./union
struct Thing {
        union {
                unsigned int               value;                /*           4 */
                unsigned char              bytes[3];             /*           3 */
        };
[...]

構造体に unsigned value:24 があり、誰かが共用体を追加して、構造体のサイズを誤って 3 バイトから 4 バイトに増やした、似たようなコードがいくつかありました。ユニオンを「パック」として定義しようとすると、同じことが起こります。サイズはまだ 4 です。この動作は C++ 仕様どおりですか? 説明は何ですか?

後で編集:「C 仕様」を「C++ 仕様」に置き換えました。

4

3 に答える 3

1

パックされた属性を匿名共用体に見逃しました。次の例を検討してください。

#define PACKED __attribute__((__packed__))
struct S1 { unsigned value:24; } PACKED ;
struct S2 { union { char a[3]; unsigned value:24; };  } PACKED ;
struct S3 { union { char a[3]; unsigned value:24; } PACKED ;  };


int main() {
   std::cout << sizeof(S1) << std::endl;
   std::cout << sizeof(S2) << std::endl;
   std::cout << sizeof(S3) << std::endl;
}

出力:

3
4
3

パックされた属性は少し奇妙です。適切な結果を得るために、可能なすべての組み合わせを常にテストしようとしています。

于 2012-09-12T08:39:52.940 に答える
0

まず、__attribute__((__packed__))gcc の拡張機能であるため、標準では、それによって何が起こるか、何が起こらないかについて何も述べていません。

ただし、一般に、コンパイラはビットフィールド間に適切と思われるパディングを挿入することができます。特に、これを与えるコンパイラを見てきました:

 struct
 {
     short a : 8;
     int b : 8;
 }

b を 32 ビット境界に揃えます。

基本的に、ビットフィールドを使用する場合は、自分で行います。フィールドの順序またはパディングの保証はありません。唯一の保証は、ビットフィールドのサイズです。

于 2012-09-12T08:44:07.620 に答える
0

質問は C++ としてタグ付けされていますが、C 仕様について言及しています。私の知る限り、その点でCとC ++には違いがあります。C では、ビットフィールドは整数型のみにすることができますが、C++ では任意の整数型を使用できます。

ビットフィールドは整数型にマップされるため、ビットフィールドのサイズは常に 1、2、または 4 であると予想されます。

したがって、これにより sizeof 3 が得られます。

struct Thing
{
    union
    {
        // without 'short' int would be assumed -> 4 bytes
        unsigned short value:15; // -> maps to short -> 2 bytes
        uint8_t bytes[3];        // -> 3 bytes, so the whole union is 3 bytes long
    };
}

ではvalue:24、常に最も近い整数型、つまり整数にマップされます。

于 2012-09-12T08:47:49.140 に答える