Linuxのcで構造体を使用しています。私はビットフィールドと "packed"属性を使い始め、奇妙な動作に遭遇しました。
struct t1
{
int a:12;
int b:32;
int c:4;
}__attribute__((packed));
struct t2
{
int a:12;
int b;
int c:4;
}__attribute__((packed));
void main()
{
printf("%d\n",sizeof(t1)); //output - 6
printf("%d\n",sizeof(t2)); //output - 7
}
なぜ両方の構造-まったく同じ-はバイト数が異なるのですか?
あなたの構造は「まったく同じ」ではありません。最初のビットフィールドには3つの連続するビットフィールドがあり、2番目のビットフィールドには1つのビットフィールド、(非ビットフィールド)int、そして2番目のビットフィールドがあります。
これは重要です:連続する(ゼロ以外の幅の)ビットフィールドは単一のメモリ位置にマージされますが、ビットフィールドの後に非ビットフィールドが続くと、別個のメモリ位置になります。
最初の構造には1つのメモリロケーションがあり、2番目の構造には3つのメモリロケーションがあります。最初の構造体ではなく、2番目の構造体でb
メンバーのアドレスを取得できます。 b
メンバーへのアクセスは、2番目の構造体のa
またはc
へのアクセスと競合しませんが、最初の構造体ではアクセスします。
ビットフィールドメンバーがsensでそれを「閉じた」直後に非ビットフィールド(または長さがゼロのビットフィールド)があると、異なる/独立したメモリロケーション/オブジェクトになります。コンパイラーは、最初の構造体のようにビットフィールド内にb
メンバーを「パック」できません。
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
のようなバイト境界以外の整数へのアクセスは遅いため、おそらくこれを行う必要があります。