如果 (mask & VALUE) 或者 如果 ((mask & VALUE) == VALUE)?

40

你可能熟悉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语句中使用较长的版本比在条件语句测试中更有意义。)


7
现在请使用口罩和ALL_FLAGS来做。不再是同样的方法。 - Hans Passant
4
== 的优先级高于 &,因此您需要在条件中使用括号:if ((mask & FLAG3) == FLAG3) - casablanca
6个回答

83

构造语句 if ((mask & FLAG3) == FLAG3) 检测在 mask 中是否全部的 FLAG3 位都存在;if (mask & FLAG3) 则检测是否至少有一个存在。

如果你确认 FLAG3 只有一位被设置,那么这两种写法是等效的。但如果你要定义复合条件,明确地检测所有位是否存在能够使代码更加清晰易读。


如果 FLAG == 0(这种情况确实可能发生),它的行为也会有所不同。 - peterchen

3

当涉及到位集(bitset)时,如果你只需要比较一个单独的位(bit),那么使用if(mask & value)是可以的。

但是,假设你有一个存储在int32中的IP地址,并且你想知道它是否为192.168.*,那么你需要执行以下操作:

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

2

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

显然,如果您要检查的值由多个位组成,则无法执行第二个选项。在这种情况下,您必须使用第一个选项。如果您同时检查几个位,那显然也适用。


2
即使在这些语句等效的单比特值中,我总是更喜欢显式比较。这样可以使意图更加清晰。"(x & Flag) == Flag" 是一种已经建立的模式,我可以一眼处理和识别它。
我通常更喜欢显式转换而不是隐式转换。我会为失败状态(例如,我写 "if (file)" 而不是 "if (file.good())")做出例外,但是当处理数字时,0 不是 "失败状态",它像其他数字一样。我不喜欢在布尔上下文中对待它有所不同。

你的第一点代码不正确。由于C和C++中的运算符优先级,您需要添加括号以获得预期的效果。这是一个常见的陷阱。 - ChrisN

1
第一个结构体,if (mask & FLAG3) 的意思是“如果标志和掩码中至少有一个公共位”。例如,如果在 formats 和 supported_formats 之间有任何一位相同,则 if (formats & supported_formats) 将为真。
第二个结构体,if (mask & FLAG3) == FLAG3 的意思是“如果掩码中设置的所有位都设置在 FLAG3 中”。例如,如果 things_you_have 中包含了 things_required 中的所有物品,则 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的情况,建议使用第二个结构编写代码,以避免在标志值更改时出现奇怪的问题。除非您的分析器告诉您要挤出每个操作,否则请明确表达。

1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接