23

Linuxでcの構造体を扱っています。ビット フィールドと「packed」属性を使い始めたところ、奇妙な動作に遭遇しました。

struct __attribute__((packed)) {
    int a:12;
    int b:32;
    int c:4;
} t1;

struct __attribute__((packed))  {
    int a:12;
    int b;
    int c:4;
}t2;

void main()
{
    printf("%d\n",sizeof(t1)); //output - 6
    printf("%d\n",sizeof(t2)); //output - 7
}

まったく同じである両方の構造が異なるバイト数を取るのはなぜですか?

4

2 に答える 2

39

あなたの構造は「まったく同じ」ではありません。最初のものには3つの連続したビットフィールドがあり、2番目のものには1つのビットフィールド、(非ビットフィールド) int、そして2番目のビットフィールドがあります。

これは重要です。連続する (幅が 0 でない) ビット フィールドは 1 つのメモリ ロケーションにマージされますが、ビット フィールドの後に非ビット フィールドが続く場合は個別のメモリ ロケーションになります。

最初の構造には 1 つのメモリ ロケーションがあり、2 番目の構造には 3 つのメモリ ロケーションがあります。最初の構造体ではなく、2 番目の構造体でメンバーのアドレスを取得できbます。メンバーへのアクセスは、2 番目の構造体のorbへのアクセスと競合しませんが、最初の構造体では競合します。ac

ビットフィールドメンバーの直後に非ビットフィールド(または長さゼロのビットフィールド)があると、ある意味でそれを「閉じる」と、その後に続くのは異なる/独立したメモリロケーション/オブジェクトになります。コンパイラはb、最初の構造体のようにビットフィールド内にメンバーを「パック」できません。

于 2014-09-13T11:41:39.023 に答える
25
struct t1 // 6 bytes
{
    int a:12; // 0:11
    int b:32; // 12:43
    int c:4;  // 44:47
}__attribute__((packed));

struct t1 // 7 bytes
{
    int a:12; // 0:11
    int b;    // 16:47
    int c:4;  // 48:51
}__attribute__((packed));

レギュラーint bはバイト境界に揃える必要があります。したがって、その前にパディングがあります。cこのパディングのすぐ隣に置くとa、パディングは不要になります。のような非バイト境界の整数へのアクセスint b:32は遅いため、おそらくこれを行う必要があります。

于 2014-09-13T11:41:20.177 に答える