2012-11-14 31 views
9

我在C++中使用枚舉來製作使用二進制標誌的有限狀態機。它看起來像:如何使用超過max int的值允許枚舉?

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 

}; 

有些狀態是不兼容的,所以我使用位運算符來管理它們。現在,我的編譯器說:

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

這是正確的方式來聲明這個枚舉?我喜歡避免警告,我該如何解決這個問題?

+1

不是一個答案,但是這將是簡單得多寫和讀,如果值寫爲十六進制的常數。 –

+9

@PeteBecker:他們實際上*是*寫成十六進制常量 - 但看起來他正在使用他應該用於十進制常量的數字(例如,他有0x00000512,它應該是512或0x200)。 –

+0

@JerryCoffin - 哎呀。 –

回答

10

(注:讓我回答完整,我會的東西我沒加沒有時間注意,但其他人指出:你使用的是前綴0x,這意味着你的數字將被解釋爲十六進制數,它們實際上不是兩個數的冪,並且你的位標測試不會起作用!)

如果您的枚舉失控,請不要使用枚舉類型。使用類似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... 
} 

...如果你想設置所有位爲假,你會跟去:

state.reset(); 
+4

這是一個比我更好的答案,因爲你糾正了真正的潛在問題。對標誌集合使用'std :: bitset',而不是枚舉。甚至比使用枚舉索引更好的是將它封裝在具有'std :: bitset'作爲具有命名成員訪問函數的私有成員的類中。 'class VStates {public:bool is_dry()const {return bits [1]; } ...};' –

+0

@DavidStone謝謝。如果包裝信息對這個受衆有興趣,那麼我的[Nstate庫](http://hostilefork.com/nstate/)可能是有趣的... – HostileFork

+0

我可能最終會使用它。我目前正在開發一個應用程序,其中2/3的時間花在複製數據上。我的相關數據結構減少了50%,運行時間略少於30%,而且似乎至少有一部分我的應用程序可能適用於該解決方案。 –

0

使用較小的數字。一個枚舉只能和一個long一樣大。長的大小取決於編譯器,但典型的大小是32位或64位。我看到一些10位十六進制數字,那些太大了。

3

如果您正在使用C++ 11,你可以聲明一個強類型枚舉了定義類型爲unsigned long long_int64在Windows,但你應該使用便攜式uint64_t),如果擴展你的範圍遠遠不夠。

由於勒夫的鏈接,C++ 11枚舉用法的示例:Strongly Typed Enums

+0

參見例如[這個維基百科鏈接](http://en.wikipedia.org/wiki/C++11#Strongly_typed_enumerations)強類型枚舉,以及如何定義它們。使用不同的整數類型。 –

+0

@JoachimPileborg謝謝,介意如果我使用該鏈接來改善答案? –

+0

當然,繼續。 :) –

12

在C++ 11,可以指定的基礎類型枚舉的。

#include <cstdint> 

enum VStates : uint64_t { 
    // Values 
} 

在附註中,我建議不要計算出所有這些2的冪。通過編寫一個十六進制常量,但在給出它的基數爲10的數字後,你的計算出錯了。然而,而不是重新計算所有這些,我建議是這樣的:

#include <cstdint> 

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

那麼你一定不要犯了一個錯誤。後綴ULL確保文字被接受爲至少一個64位寬整數。

4

枚舉有31個非零值,因此它們都可以放入一個32位無符號值。問題是這裏的值不是位值。可以將它們寫爲十進制值(從前面刪除0x)或將它們寫爲十六進制值(0x01,0x02,0x04,0x08,0x10,0x20,0x40等)。我個人不喜歡它,但有些人寫這種不斷的變化與1 < < 0,1 < < 1,1 < < 2,1 < < 3等

+2

我很好奇你不喜歡輪班?他們不太容易出錯,並快速瀏覽一下枚舉,你馬上知道你可以對它使用按位操作。 – Joe

+2

@Joe - 它純粹是美感。它們不像十六進制值那麼容易出錯,我認爲它們很醜。 –