标志、枚举 (C)

发布于 2024-08-09 12:28:38 字数 481 浏览 2 评论 0 原文

我不太习惯使用标志进行编程,但我想我刚刚发现了它们有用的情况:

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

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

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

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

你究竟如何处理这些东西?

I'm not very used to programming with flags, but I think I just found a situation where they'd be useful:

I've got a couple of objects that register themselves as listeners to certain events. What events they register for is dependent on a variable that is sent to them when they are constructed. I think a nice way to do this would be to send bitwise OR connected variables, like such: TAKES_DAMAGE | GRABBABLE | LIQUID, etc. Then, in the constructor, the object can check what flags are set and register it self as listener for the ones that are.

But this is where I get confused. Preferably, the flags would be in an enum. But that is also a problem. If we have got these flags:

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

Then sending the flag SOME_OTHER (3) will be the same as sending GRABBABLE | LIQUID, will it not?

How exactly do you deal with this stuff?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

俏︾媚 2024-08-16 12:28:38

您的枚举需要是 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 设置为可抓取 | 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

Your enumeration needs to be powers of two :

enum
{
    TAKES_DAMAGE = 1,
    GRABBABLE = 2,
    LIQUID = 4,
    SOME_OTHER = 8
};

Or in a more readable fashion :

enum
{
    TAKES_DAMAGE = 1 << 0,
    GRABBABLE = 1 << 1,
    LIQUID = 1 << 2,
    SOME_OTHER = 1 << 3
};

Why ? Because you want to be able to combine flags with no overlapping, and also be able to do this:

if(myVar & GRABBABLE)
{
    // grabbable code
}

... Which works if the enumeration values look like this :

 TAKES_DAMAGE: 00000001
 GRABBABLE:    00000010
 LIQUID:       00000100
 SOME_OTHER:   00001000

So, say you've set myVar to GRABBABLE | TAKES_DAMAGE, here's how it works when you need to check for the GRABBABLE flag:

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

If you'd set myVar to LIQUID | SOME_OTHER, the operation would have resulted in :

 myVar:     00001100
 GRABBABLE: 00000010 [AND]
 -------------------
            00000000 // zero => converts to false
甚是思念 2024-08-16 12:28:38

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

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

another way of storing flags is to not bother with the underlying type at all. when using an enum, the enum values are stored by default into an unsigned int, which is 32 bits on a common computer. this gives you with only 32 possible flags: while certainly much, there are some cases where it is not sufficient.

now you can define your flag set this way:

typedef struct
{
    int takes_damage : 1;
    int grabbable    : 1;
    int liquid       : 1;
    int some_other   : 1;
} flags;

if you never encountered this, the ': 1' part tells the compiler to only use 1 bit to store this struct member.

now you can define a variable to hold the flags, and work with those flags:

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();

this method allows you to define any number of flags, without limitation, and you can extend your flag set at any time without fearing an overflow. the drawback is that testing a subset of the flags is more cumbersome and necessitate more code.

清引 2024-08-16 12:28:38

是的。相反,让你的枚举成员的幂为 2:

enum
{
    TAKES_DAMAGE = (1 << 0),
    GRABBABLE = (1 << 1),
    LIQUID = (1 << 2),
    SOME_OTHER = (1 << 3)
};

Yes. Instead, make your enum members powers of 2:

enum
{
    TAKES_DAMAGE = (1 << 0),
    GRABBABLE = (1 << 1),
    LIQUID = (1 << 2),
    SOME_OTHER = (1 << 3)
};
£冰雨忧蓝° 2024-08-16 12:28:38

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

You should make the flags only powers of two, i.e. each is a bit in whatever data type you're storing this in, and nothing overlaps when you bitwise OR.

稍尽春風 2024-08-16 12:28:38

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

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

然后,只需对它们执行按位或即可。

Can't you just set the values in the enum?

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

Afterwards, just perfom bit-wise OR on them.

亽野灬性zι浪 2024-08-16 12:28:38

你需要

enum
{
    TAKES_DAMAGE = 1,
    GRABBABLE = 2,
    LIQUID = 4,
    SOME_OTHER = 8
};

you need

enum
{
    TAKES_DAMAGE = 1,
    GRABBABLE = 2,
    LIQUID = 4,
    SOME_OTHER = 8
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文