2012-11-14 33 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 - 它纯粹是美感。它们不像十六进制值那么容易出错,我认为它们很丑。 –