我不习惯使用标志进行编程,但我认为我只是发现它们有用的情况:
我有几个对象将自己注册为某些事件的监听器。他们注册的事件取决于构造它们时发送给它们的变量。我认为一个很好的方法是发送按位OR连接变量,如:TAKES_DAMAGE | GRABBABLE | LIQUID等等。然后,在构造函数中,对象可以检查设置了哪些标志,并将其自身注册为侦听器。
但这是我感到困惑的地方。优选地,标志将在枚举中。但这也是一个问题。如果我们有这些旗帜:
enum
{
TAKES_DAMAGE,/* (0) */
GRABBABLE, /* (1) */
LIQUID, /* (2) */
SOME_OTHER /* (3) */
};
然后发送标志SOME_OTHER(3)将与发送GRABBABLE |相同LIQUID,不是吗?
你究竟如何处理这些事情?
答案 0 :(得分:51)
您的枚举必须是2的幂:
enum
{
TAKES_DAMAGE = 1,
GRABBABLE = 2,
LIQUID = 4,
SOME_OTHER = 8
};
或者以更易读的方式:
enum
{
TAKES_DAMAGE = 1 << 0,
GRABBABLE = 1 << 1,
LIQUID = 1 << 2,
SOME_OTHER = 1 << 3
};
为什么?因为您希望能够组合标志而不重叠,并且能够执行此操作:
if(myVar & GRABBABLE)
{
// grabbable code
}
...如果枚举值如下所示,则可以使用:
TAKES_DAMAGE: 00000001
GRABBABLE: 00000010
LIQUID: 00000100
SOME_OTHER: 00001000
所以,假设您已将myVar
设置为GRABBABLE | TAKES_DAMAGE
,以下是您需要检查GRABBABLE标志时的工作原理:
myVar: 00000011
GRABBABLE: 00000010 [AND]
-------------------
00000010 // non-zero => converts to true
如果您将myVar
设置为LIQUID | SOME_OTHER
,则操作会导致:
myVar: 00001100
GRABBABLE: 00000010 [AND]
-------------------
00000000 // zero => converts to false
答案 1 :(得分:28)
另一种存储标志的方法是根本不打扰底层类型。当使用枚举时,枚举值默认存储在unsigned int中,在普通计算机上为32位。这只给你32个可能的标志:虽然很多,但有些情况下还不够。
现在你可以用这种方式定义你的标志:
typedef struct
{
int takes_damage : 1;
int grabbable : 1;
int liquid : 1;
int some_other : 1;
} flags;
如果您从未遇到过这种情况,则“:1”部分告诉编译器仅使用1位来存储此结构成员。
现在您可以定义一个变量来保存标志,并使用这些标志:
flags myflags = {1,0,0,1}; // defines a variable holding a set of flags, with an initial value of takes_damage & some_other
myflags.liquid = 1; // change the flags to include the liquid
if ( myflags.takes_damage ) // test for one flag
apply_damage();
if ( myflags.liquid && myflags.some_other ) // test for multiple flags
show_strange_behavior();
此方法允许您定义任意数量的标志,没有限制,您可以随时扩展您的标志集,而不必担心溢出。缺点是测试标志的子集更加麻烦,需要更多的代码。
答案 2 :(得分:5)
是。相反,让你的枚举成员的权力为2:
enum
{
TAKES_DAMAGE = (1 << 0),
GRABBABLE = (1 << 1),
LIQUID = (1 << 2),
SOME_OTHER = (1 << 3)
};
答案 3 :(得分:4)
你应该使标志只有2的幂,即每个数据类型都存在于你所存储的数据类型中,并且当你按位OR时没有任何重叠。
答案 4 :(得分:4)
你不能只在枚举中设置值吗?
enum {
TAKES_DAMAGE = 1,
GRABBABLE = 2,
LIQUID = 4
}
之后,只需按顺序对它们进行操作。
答案 5 :(得分:3)
你需要
enum
{
TAKES_DAMAGE = 1,
GRABBABLE = 2,
LIQUID = 4,
SOME_OTHER = 8
};