39

您可能熟悉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语句中比在条件语句测试中更有意义。)

4

6 回答 6

83

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

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

于 2011-01-10T16:59:15.437 回答
3

当它用于 bitset 时,因此您只需比较一个,就可以拥有if(mask & value).

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

if((ip & 0xFFFF0000) == 0xC0A80000) // assuming some endianness representation.
于 2011-01-10T16:56:08.987 回答
2

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

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

于 2011-01-10T16:59:42.053 回答
2

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

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

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

于 2011-01-10T17:04:07.447 回答
1

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

于 2011-01-10T16:57:23.313 回答
1

第一个构造if (mask & FLAG3)表示“如果标志和掩码中至少有一个公共位”。例如,if (formats & supported_formats)如果格式和supported_formats 之间有任何共同点,则为真。

第二个构造if (mask & FLAG3) == FLAG3意味着“如果 FLAG3 中的所有设置位都设置在掩码中”。例如, if (things_you_have & things_required) == things_required如果所有things_required 都在 things_you_have 中,则为真。

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

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

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

于 2018-10-31T07:01:03.860 回答