【问题标题】:if (mask & VALUE) or if ((mask & VALUE) == VALUE)?if (mask & VALUE) 还是 if ((mask & VALUE) == VALUE)?
【发布时间】:2011-01-10 16:53:29
【问题描述】:

您可能熟悉enum 位掩码方案,例如:

enum Flags {
    FLAG1 = 0x1,
    FLAG2 = 0x2,
    FLAG3 = 0x4,
    FLAG4 = 0x8,

    NO_FLAGS = 0,
    ALL_FLAGS = FLAG1 | FLAG2 | FLAG3 | FLAG4
};

f(FLAG2 | FLAG4);

我见过很多代码,然后测试掩码中的某个位,例如

if ((mask & FLAG3) == FLAG3)

但这不就相当于这个吗?

if (mask & FLAG3)

使用第一个版本有什么理由吗?在我看来,第二个较短的版本更清晰。

也许是 C 程序员遗留下来的习惯,他们认为应该将真值转换为 1? (尽管即使在那里,较长的版本在赋值或return 语句中比在条件语句测试中更有意义。)

【问题讨论】:

  • 现在用掩码和 ALL_FLAGS 来做。不再一样了。
  • == 的优先级高于 &,因此您的条件中需要括号:if ((mask & FLAG3) == FLAG3)

标签: c++ bitmask


【解决方案1】:

构造 if ((mask & FLAG3) == FLAG3) 测试 FLAG3 中的 所有 位是否存在于掩码中; if (mask & FLAG3) 测试是否存在 any

如果您知道 FLAG3 恰好设置了 1 个位,它们是等价的,但如果您可能定义复合条件,那么养成显式测试所有位的习惯会更清楚,如果这就是您的意思。

【讨论】:

  • 如果FLAG == 0(这...可能发生),它的行为也会有所不同
【解决方案2】:

当它是一个位集时,你只需要比较一个单个位,可以有if(mask & value)

但是,假设你有一个 IP 地址存储在 ant int32 上,并且你想知道它是否是 192.168.*,那么你将不得不这样做:

if((ip & 0xFFFF0000) == 0xC0A80000) // assuming some endianness representation.

【讨论】:

    【解决方案3】:

    如果结果非零,则您的条件为真。在您的示例中,两个操作的结果将是等效的,并且第二个选项甚至可能会稍微快一些,因为某些 CPU 可以比其他任意数字更容易测试零,但是:

    显然,如果您要检查的值包含多于一位,则不能执行第二个选项。在这种情况下,您必须使用第一个选项。如果您同时检查多个位,这显然也适用。

    【讨论】:

      【解决方案4】:

      即使对于这些语句实际上等效的单位值,我也总是倾向于显式比较。

      1. 它使意图更清晰。我们真的对比较标志感兴趣(x & Flag) == Flag 是一个既定的模式,我可以在眨眼间处理和识别它。

      2. 我通常更喜欢显式转换而不是隐式转换。我对失败状态做了一个例外(例如,我写了if (file) 而不是if (file.good()))但是在处理数字时,0 不是“失败状态”,它是一个和其他数字一样的数字。我不喜欢在布尔上下文中区别对待。

      【讨论】:

      • 第 (1) 点中的代码不正确。由于 C 和 C++ 中的运算符优先级,您需要添加括号才能获得预期的效果。一个常见的问题。
      【解决方案5】:

      if 采用布尔值 (bool)。前一个表达式直接为bool类型,而后者是一个数值,会隐式转换为bool

      【讨论】:

        【解决方案6】:

        第一个构造,if (mask & FLAG3) 表示“如果标志和掩码中至少有一个公共位”。例如,如果 any 位在 format 和 supported_formats 之间是共同的,if (formats & supported_formats) 将是 true。

        第二个构造,if (mask & FLAG3) == FLAG3 表示“如果 FLAG3 中的所有设置位都设置在掩码中”。例如,如果 all things_required 位于 things_you_have 中,if (things_you_have & things_required) == things_required 将为真。

        以下是一些特殊情况的快速介绍:

        • 对于FLAG_WITH_EXACTLY_ONE_BIT_SET,两种情况都有效。
        • 对于OBSOLETE_FLAG_SET_TO_ZERO,第一种情况总是返回false。
        • 对于FLAG_WITH_MULTIPLE_BITS_REQUIREDFLAG_WHICH_IS_REALLY_TWO_FLAGS_COMBINED_WITH_AN_OR,第一种情况不应该返回true。第二种情况正确返回。

        如果您遇到 FLAG_WITH_EXACTLY_ONE_BIT_SET 的情况,您应该使用第二个构造进行编码,以避免在标志值更改时出现奇怪的问题。除非你的分析器告诉你要挤出每一个操作,否则要明确。

        【讨论】:

          猜你喜欢
          • 2011-02-27
          • 2011-12-24
          • 1970-01-01
          • 2015-02-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-12
          相关资源
          最近更新 更多