19

我不太习惯使用标志进行编程,但我想我只是发现了一种有用的情况:

我有几个对象将自己注册为某些事件的侦听器。它们注册的事件取决于构造它们时发送给它们的变量。我认为这样做的一个好方法是发送按位或连接的变量,例如:TAKES_DAMAGE | GRABBABLE | LIQUID等。然后,在构造函数中,对象可以检查设置了哪些标志并将其注册为监听器。

但这就是我感到困惑的地方。最好,标志将位于enum. 但这也是一个问题。如果我们有这些标志:

enum
{
    TAKES_DAMAGE,/* (0) */
    GRABBABLE, /* (1) */
    LIQUID, /* (2) */
    SOME_OTHER /* (3) */
};

那么发送标志SOME_OTHER(3)将与发送相同GRABBABLE | LIQUID,不是吗?

你具体是怎么处理这些东西的?

4

6 回答 6

61

您的枚举需要是二的幂:

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

因此,假设您已设置myVarGRABBABLE | TAKES_DAMAGE,当您需要检查 GRABBABLE 标志时,它的工作方式如下:

 myVar:     00000011
 GRABBABLE: 00000010 [AND]
 -------------------
            00000010 // non-zero => converts to true

如果您设置myVarLIQUID | SOME_OTHER,则该操作将导致:

 myVar:     00001100
 GRABBABLE: 00000010 [AND]
 -------------------
            00000000 // zero => converts to false
于 2009-10-27T14:42:21.533 回答
31

另一种存储标志的方法是根本不关心底层类型。使用枚举时,枚举值默认存储为无符号整数,在普通计算机上为 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();

此方法允许您无限制地定义任意数量的标志,并且您可以随时扩展标志集而不必担心溢出。缺点是测试标志的子集更麻烦并且需要更多代码。

于 2009-10-27T16:01:43.497 回答
6

是的。相反,使您的枚举成员的幂为 2:

enum
{
    TAKES_DAMAGE = (1 << 0),
    GRABBABLE = (1 << 1),
    LIQUID = (1 << 2),
    SOME_OTHER = (1 << 3)
};
于 2009-10-27T14:42:47.293 回答
4

您应该使标志仅是 2 的幂,即每个标志在您存储它的任何数据类型中都有一点,并且当您按位或时没有任何重叠。

于 2009-10-27T14:42:10.287 回答
4

你不能只设置枚举中的值吗?

enum {
 TAKES_DAMAGE = 1,
 GRABBABLE    = 2,
 LIQUID       = 4
}

之后,只需对它们执行按位 OR 即可。

于 2009-10-27T14:42:46.930 回答
3

你需要

enum
{
    TAKES_DAMAGE = 1,
    GRABBABLE = 2,
    LIQUID = 4,
    SOME_OTHER = 8
};
于 2009-10-27T14:42:31.957 回答