10

バイナリフラグを使用して有限状態マシンを作成するために、C ++で列挙型を作成しています。次のようになります。

enum VStates
{
    NEUTRAL         =   0x00000000,     // 000000
    //  Physical Status
    DRY             =   0x00000001,     // 000001
    WET             =   0x00000002,     // 000010
    HOT             =   0x00000004,     // 000100
    COLD            =   0x00000008,     // 001000
    BURNED          =   0x00000016,     // etc..
    FROZEN          =   0x00000032,
    EROS            =   0x00000064,     // 
    THANATOS        =   0x00000128,     // 
    SLEEP           =   0x00000256,
    STUNNED         =   0x00000512,
    PARALYZED       =   0x00001024,
    POISONED        =   0x00002048,     //
    BLIND           =   0x00004096,
    SOFT            =   0x00008192,     // Flexible
    TOUGH           =   0x00016384,     // Resistent
    MAGNETIZED      =   0x00032768,
    POSSEDERUNT     =   0x00131072,     //
    // Mental Status
    ANGRY           =   0x00262144,
    DRUGGED         =   0x00524288, // Drugs Meaning
    HORNY           =   0x01048576, // Sexual Meaning
    // Material Status
    METAL           =   0x02097152,
    WOOD            =   0x04194304,
    GLASS           =   0x08388608,
    AIR             =   0x16777216,
    EARTH           =   0x33554432,
    DUST            =   0x67108864,
    LIGHT           =   0x134217728,
    SHADOW          =   0x268435456,
    WATER           =   0x536870912,
    // Total Status
    PROTECTED       =   0x1073741824,
    INVULNERABLE    =   0x2147483648

};

一部のステータスは互換性がないため、Bitwise 演算子を使用して管理しています。今、私のコンパイラは言う:

warning: integer constant is too large for 'long' type

これは、この列挙型を宣言する正しい方法ですか? 警告を避けたいので、どうすればこの問題を解決できますか?

4

5 に答える 5

13

C++11 では、列挙型の基になる型を指定できます。

#include <cstdint>

enum VStates : uint64_t {
    // Values
}

余談ですが、これらの 2 の累乗をすべて計算しないことをお勧めします。16 進数の定数を書き込んで、10 進数の数字を指定して計算を間違えました。ただし、それらすべてを再計算するのではなく、次のようにすることをお勧めします。

#include <cstdint>

enum VStates : uint64_t {
    NEUTRAL = 0ULL,
    DRY = 1ULL << 0,
    WET = 1ULL << 1,
    HOT = 1ULL << 2,
    COLD = 1ULL << 3,
    // etc.
}

そうすれば、あなたは間違いを犯さないはずです。ULLサフィックスにより、リテラルが少なくとも 64 ビット幅の整数として受け入れられることが保証されます。

于 2012-11-14T19:24:40.450 に答える
11

(注:私の答えを完全にするために、私が気付くのに時間がかからなかったが他の人が指摘したことを追加します:0xプレフィックスを使用しています。つまり、数字は16進数として解釈されます。実際にはそうではありません2 のべき乗であると、ビットフラグ テストが機能しません!)

このように列挙型が制御不能になっている場合は、列挙型を使用しないでください。のようなものを使用しstd::bitsetます。次に、列挙型は、セット内のビットの位置の名前の単純な番号付きリストにすることができます...そして、列挙空間を指数関数的に使い果たすことはありません!

例えば:

enum VState {
    NEUTRAL,
    DRY,
    WET,
    COLD,
    BURNED,
    FROZEN,
    /* ... */
    VState_Max
};

bitset<VState_Max> state;

state[COLD] = true;
if (state[COLD]) {
    cout << "I am cold\n";
}

これで、列挙型は小さくて維持しやすい数値になり、64 ビット プラットフォームなどについて心配する必要がなくなりました。

元の例でNEUTRALに「0」の値を指定したことに注意してください。あなたの意図が、これを他のものと組み合わせて使用​​できるようにすることであった場合... でstate = NEUTRAL | INVULNERABLE | SHADOWあり、個別にテストできるなどNEUTRAL、以前は機能しなかったでしょう。これで...ビットセットにインデックスを付けるために列挙に保持するだけです。

ただし、「何も設定されていない」という名前を意図している場合は、列挙型から削除し、代わりにビットが設定されていないことをテストします。

if (state.none()) {
    // we are in the "NEUTRAL" state of nothing set...
}

...そして、すべてのビットを false に設定する場合は、次のようにします。

state.reset();
于 2012-11-14T19:26:34.787 に答える
4

列挙には 31 個のゼロ以外の値があるため、それらはすべて 32 ビットの符号なし値に収まります。問題は、ここの値がビット値ではないことです。10進数で書く(0x先頭の を除いて)か、16進数で書くか(0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40など) 個人的には好きじゃないけど、こう書く人もいるシフト付き定数の種類: 1<<0、1<<1、1<<2、1<<3 など。

于 2012-11-14T19:25:59.980 に答える
3

C++11 を使用している場合、定義された型を持つ厳密に型指定された列挙型をunsigned long long( _int64Windows ではおそらくポータブルを使用する必要がありますがuint64_t) として宣言できますが、それによって範囲が十分に拡張されます。

C++11 列挙型の使用例へのリンクを提供してくれた Joachim に感謝します:厳密に型指定された列挙型

于 2012-11-14T19:21:50.103 に答える
0

小さい数値を使用してください。enum は、long と同じ大きさにしかできません。long のサイズはコンパイラによって異なりますが、一般的なサイズは 32 ビットまたは 64 ビットです。10 桁の 16 進数が表示されていますが、大きすぎます。

于 2012-11-14T19:21:47.463 に答える