【问题标题】:Combining Enum Value using Bitmask使用位掩码组合枚举值
【发布时间】:2011-02-07 11:32:12
【问题描述】:

我知道可以在枚举值中使用位掩码,但我不知道如何创建它。

我有一个简单的枚举:

enum State
{
    minimizing = 0,
    maximizing,

    minimized,
    maximized
};

状态始终为State.minimizedState.maximized,并且可以在调整大小时具有其他状态。所以有些东西可以最大化和最小化

【问题讨论】:

    标签: c++ c enums bitmask


    【解决方案1】:

    我将假设myState 具有您的enum State 的类型。

    enum 的传统用法是创建这种类型的变量可以采用的常量值。您希望将变量myState 设置为enum 中定义的值的组合

    enum 将 1、2、4 和 8 定义为有效值,但您希望能够将变量设置为 4 | 2 = 6。虽然 C 对所有 enum 使用实现定义的 int 类型,但在 C++ 中并非如此。 myState = 6 在 C++ 中无效。实际上,myState = 4 在 C++ 中无效,您需要显式转换或使用 enum 的常量名称之一。

    尽管在 C 语言中可行,但将 myState 设置为未由其类型定义的值(例如设置为 6)并不是一个好习惯。

    在您的情况下,似乎随之而来的解决方案是:

    typedef enum {
        OTHER,
        MINIMIZED,
        MAXIMIZED
    } win_size_t;
    
    typedef struct {
        win_size_t current;
        win_size_t next;
    } state_t;
    
    state_t myState;
    

    这样,您可以独立地写入字段currentnext

    如果您仍然想要位字段,您可以设置结构元素的大小(以位为单位)。这有点危险,位域的实现取决于你的编译器。我什至不确定编译器是否会接受在位字段中使用枚举类型(在 C 中应该可以,因为 enums 是 int)。

    typedef struct {
        win_size_t current : 2;  // not tested
        win_size_t next : 2;
    } state_t;
    

    前面给出的解决方案当然是有效的。我的观点是,如果你的变量 myState 有你的 enum State 作为类型,它应该只使用 enum 的成员作为其值,而不是组合。

    可能myState有其他类型,我知道什么。


    如果myState 不属于enum State 类型,则可以组合使用enum 中定义的常量。

    enum State {
        MINIMIZING = (1u << 0),
        MAXIMIZING = (1u << 1),
        MINIMIZED  = (1u << 2),
        MAXIMIZED  = (1u << 3),
    };
    
    unsigned int myState = 0;
    
    myState |= MAXIMIZED;  // sets that bit
    myState &= ~MAXIMIZED; // resets that bit
    

    这使您可以在一项作业中做两件事:

    myState = MAXIMIZED | MINIMIZING;
    

    还有你可能不想要的东西:

    myState = MAXIMIZED | MINIMIZED;  // does that make sense?
    

    【讨论】:

    • 谢谢!我选择了选项#1。确实,MAXIMIZED | MINIMIZED 是可能的,这毫无意义,因为有两个枚举更好的可读性。
    • 请注意,将枚举限制为位字段是未定义的行为,结果取决于编译器。如果我错了也请纠正我。
    • @DavidTóth 您似乎是正确的,谢谢! stackoverflow.com/a/33590935/108802
    【解决方案2】:

    对枚举中的每个值使用不同的位,例如:

    enum State 
    {
      minimizing = 0x01, // 00000001
      maximizing = 0x02, // 00000010
      minimized  = 0x04, // 00000100
      maximized  = 0x08  // 00001000
    }:
    

    然后,您可以使用按位或 (minimizing | maximized) 组合多个值,并使用按位和 (bool is_minimized = (flags &amp; minimized);) 测试值。

    【讨论】:

    • 品味问题,但我更喜欢:(1u &lt;&lt; 0)(1u &lt;&lt; 1)(1u &lt;&lt; 2)(1u &lt;&lt; 3)。你的意思更清楚了。
    • 为什么要以十六进制表示法定义值? minimizing = 1 也有效
    • @NatanYellin:确实如此,但如果要再添加一个状态并且使用十进制,则必须写 16。假设您要设置两位,第 4 位和位 1. 结果是十进制的 18,比 0x12 可读性差(如果这不明显,请尝试识别在十进制 2398 中设置了哪些位。如果您有等效的 0x95E,则容易得多)。如果您对设置哪些位感兴趣,可以选择十六进制。
    【解决方案3】:

    我刚刚在 VS2012 中尝试过,如果您使用的是位域,优化器似乎可以正确组合位而无需任何帮助。

    struct BITS { int x: 1; int y:1; };
    

    然后

    BITS b;
    b.x = b.y = 1;
    

    用一条指令设置两个位。

    【讨论】:

      【解决方案4】:

      您可以通过指定枚举中的所有字段并增加 2 的幂来获得此效果,以获得位掩码效果。例如,在您的情况下:

      enum State
      {
          minimizing = 1,
          maximizing = 2,
      
          minimized = 4,
          maximized = 8
      };
      

      这样您就可以拥有(State.maximized | State.minimizing) 的组合。但是,这不会应用仅限于 State.maximizedState.minimized 的限制。如果你想这样做,你可以将它们转换为单个位,但我想在这个例子中你希望能够有一个既不最大化也不最小化的情况。

      【讨论】:

      • 通常是用 shift 来写的
      • 但是,我该如何使用它呢?就像我有:myState = minimized; if (isMaximizing) { myState = maximizing } 我想设置最大化状态,而不会丢失最小化状态
      • 那么你可以使用myState |= maximizing;。这会设置您感兴趣的位,而不会触及其他位。对于归零,使用myState &amp;= ~maximizing;。比较时要小心,myState == minimized 不起作用,你需要(myState &amp; minimized) == minimized(或!= 0)。如果我是你,我会考虑一个结构体,其中一个字段为“当前状态”,另一个字段为“下一个状态”。
      • 请注意,虽然enum State 定义了一些常量,但它没有定义它们的组合。如果myState被最小化和最大化,则结果值为0x02 | 0x04,即0x06。不是您的枚举定义的值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-13
      相关资源
      最近更新 更多