32

たとえば、次の構造体があります。

typedef struct my_struct{
    unsigned long       a;
    unsigned long       b;
    char*               c;
    unsigned int        d1  :1;
    unsigned int        d2  :4;
    unsigned int        d3  :4;
    unsigned int        d4  :23;
} my_type, *p_type;

このフィールドは現在、からまでに到達するsd3によって定義されています。#define0x000x0D

実は、d3列挙です。ですから、先に進んで交換するのは魅力的です

    unsigned int        d3  :4;

    my_enum             d3  :4;

これは安全/許可されていますか?

コードはさまざまなものでコンパイルする必要があります

  • コンパイラー(GCC、Visual Studio、組み込みのもの)
  • プラットフォーム(Win32、Linux、組み込みのもの)
  • 構成(Cとしてコンパイル、C ++としてコンパイル)

明らかに、の定義をd3そのままにして、コードで列挙型を使用したり、に割り当てたりすることはできますd3が、C++では機能しません。

4

4 に答える 4

24

これは、標準をサポートするすべてのC++コンパイラで許可されています。

C++03標準9.6/3

ビットフィールドは、整数型または列挙型(3.9.1)でなければなりません。プレーン(明示的に符号付きでも符号なしでもない)char、short、int、またはlongビットフィールドが符号付きか符号なしかは実装定義です。

C++03標準9.6/4

列挙型の値が同じ列挙型のビットフィールドに格納され、ビットフィールドのビット数がその列挙型のすべての値、元の列挙型の値、および値を保持するのに十分な数である場合ビットフィールドのは等しく比較されます。

enum BOOL { f=0, t=1 };

struct A {
    BOOL b:1;
};

void f() {
    A a;
    a.b = t;
    a.b == t // shall yield true
}

しかし、列挙型に符号なしの基になる型があるとは考えられません。

C++03標準7.2/5

列挙型の基になる型は、列挙型で定義されたすべての列挙型値を表すことができる整数型です。列挙型の基になる型として使用される整数型は実装によって定義されます。ただし、列挙子の値がintまたはunsigned intに収まらない場合を除き、基になる型はintより大きくてはなりません。

于 2012-08-16T08:38:02.303 に答える
15

答えはCとC++で異なります。これは、Cの場合です。

Cでは、ビットフィールドは、、に制限されてsigned intおりunsigned int_Boolこのintコンテキストでは最初の2つのうちのいずれかになります。コンパイラの実装者は、そのリストに好みに合わせて追加できますが、サポートするタイプを文書化する必要があります。

したがって、質問に答えるために、コードがすべてのCコンパイラに移植可能であることを絶対に確認したい場合は、いいえ、enum型を使用することはできません。

現在の標準の対応する段落は次のとおりです。

ビットフィールドは、_Boolの修飾バージョンまたは非修飾バージョン、signed int、unsigned int、またはその他の実装定義型である型を持っている必要があります。アトミックタイプが許可されるかどうかは、実装によって定義されます。

于 2012-08-16T08:38:29.007 に答える
9

いいえ。

ビットフィールドは、コンパイラ間で大幅に異なる方法で実装されます。ゼロと1の2つの値でビットフィールドを定義し、列挙型のビットフィールドを作成しようとすると、次の問題が発生する可能性があります。

ビットフィールドはgccとclangで署名されていませんが、VC++で署名されています。これは、0と1を格納するには、2ビットのビットフィールドが必要であることを意味します(1ビットの符号付きビットフィールドは、0と負の1のみを格納できます)。

次に、パッキングについて心配する必要があります。VC ++は、サイズが一致する場合にのみ、隣接するビットフィールドを同じバッキングストアにパックします。gccとclangのルールはわかりませんが、VC ++の場合、ビットフィールドのデフォルトのバッキングストアはintです。したがって、たとえば、boolとenumの混合である一連のビットフィールドは、VC++では非常に不十分にパックされます。

これは、C++11型の列挙型で解決することができます。

enum Foo:unsigned char {one、two};

しかし、これを1ビットビットフィールドで使用すると、gccは文句を言います。

警告:「bitfieldTest::g」は小さすぎて「enumFoo」のすべての値を保持できません[デフォルトで有効]

勝てないようです。

于 2014-11-04T06:26:08.373 に答える
-1

Cでは、ビットフィールドは、、またはタイプ(またはC99)のみを持つことができるため、これは未定義signed intint動作unsigned intです_Bool

6.5.2.1

ビットフィールドは、int、unsigned int、またはsignedintのいずれかの修飾バージョンまたは非修飾バージョンであるタイプを持っている必要があります。(修飾されている可能性のある)「プレーン」intビットフィールドの上位ビット位置が符号ビットとして扱われるかどうかは、実装によって定義されます。ビットフィールドは、指定されたビット数で構成される整数型として解釈されます。

それ以外の場合、一部のコンパイラは今日それを拡張機能として受け入れます(標準の拡張機能の実装定義の動作を参照)。

于 2012-08-16T08:50:47.200 に答える