9

C11 での作業、次の構造体:

struct S {
  unsigned a : 4;
  _Bool    b : 1;
};

unsigned4 ビットが使用される (4 バイト)として GCC によってレイアウトされ、その後_Boolに 1 ビットが使用される (4 バイト) が続き、合計サイズは 8 バイトになります。

C99 と C11 では_Bool、ビット フィールド メンバとして明確に許可されていることに注意してください。C11 標準 (およびおそらく C99 も) は、§6.7.2.1 '構造体および共用体指定子' ¶11 の下で次のように述べています。

実装では、ビットフィールドを保持するのに十分な大きさのアドレス可能なストレージユニットを割り当てることができます。十分なスペースが残っている場合、構造内の別のビットフィールドの直後に続くビットフィールドは、同じユニットの隣接するビットにパックされます。

したがって、b上記のメンバーは、メンバーに割り当てられたストレージユニットにパックされているはずでありa、合計サイズが 4 バイトの構造体になると思います。

GCC は正しく動作し、2 つのメンバーに同じ型を使用する場合、または一方がunsignedで他方が である場合にパッキングが行われますsignedが、型unsigned_Boolは GCC によって区別されすぎて正しく処理できないと見なされているようです。

誰かが標準の私の解釈を確認できますか?これは実際に GCC のバグです?

また、回避策 (コンパイラ スイッチ、プラグマなど) にも興味があり__attribute__ます。

私は gcc 4.7.0 を使用して-std=c11います (ただし、他の設定は同じ動作を示します)。

4

2 に答える 2

10

説明されている動作は、C99 および C11 標準とは互換性がありませんが、MSVC コンパイラ (通常とは異なる構造体パッキング動作を行う) とのバイナリ互換性のために提供されています。

幸いなことに、コード内で__attribute__((gcc_struct))構造体に適用するか、コマンドライン スイッチを使用して無効にすることができます (ドキュメント-mno-ms-bitfieldsを参照してください)。

于 2012-07-01T15:56:41.493 に答える
0

Mac OS X10.7.4で64ビットコンパイルを使用してGCC4.7.1(自家製)とGCC 4.2.1(LLVM / clang†)の両方を使用すると、このコードは次のモードで生成4されます。-std=c99

#include <stdio.h>

int main(void)
{
    struct S
    {
        unsigned a : 4;
        _Bool    b : 1;
    };
    printf("%zu\n", sizeof(struct S));
    return 0;
}

これは、Windowsで報告しているサイズの半分です。私には驚くほど大きいように見えますが(1バイトのサイズになると思います)、プラットフォームのルールはそれなりです。基本的に、コンパイラはあなたが望む規則に従う義務はありません。実行されているプラ​​ットフォームのルールに従う場合があり、機会があれば、実行されているプラ​​ットフォームのルールを定義する場合もあります。

この次のプログラムは、(最後に書き込まれたu.i後にアクセスするため)やや疑わしい動作をしますが、フィールドが最下位4ビットに格納され、フィールドが次のビットに格納されることを示しています。u.sab

#include <stdio.h>

int main(void)
{
    union
    {
        struct S
        {
            unsigned a : 4;
            _Bool    b : 1;
        } s;
        int i;
    } u;
    u.i = 0;
    u.s.a = 5;
    u.s.b = 1;
    printf("%zu\n", sizeof(struct S));
    printf("%zu\n", sizeof(u));
    printf("0x%08X\n", u.i);
    u.s.a = 0xC;
    u.s.b = 1;
    printf("0x%08X\n", u.i);
    return 0;
}

出力:

4
4
0x00000015
0x0000001C

†i686-apple-darwin11-llvm-gcc-4.2(GCC)4.2.1(Apple Inc.ビルド5658に基づく)(LLVMビルド2336.9.00)

于 2012-07-01T17:16:26.717 に答える