开发者

if (mask & VALUE) or if ((mask & VALUE) == VALUE)?

开发者 https://www.devze.com 2023-02-03 23:37 出处:网络
You\'re probably familiar with the enum bitmask scheme, like: enum Flags { FLAG1 = 0x1, FLAG2 = 0x2, FLAG3 = 0x4,

You're probably familiar with the enum bitmask scheme, like:

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

    NO_FLAGS = 0,
    ALL_FL开发者_JS百科AGS = FLAG1 | FLAG2 | FLAG3 | FLAG4
};

f(FLAG2 | FLAG4);

I've seen a lot of code that then tests for a certain bit in the mask like

if ((mask & FLAG3) == FLAG3)

But isn't that equivalent to this?

if (mask & FLAG3)

Is there some reason to use the first version? In my opinion, the second shorter version is more legible.

Maybe leftover habits from C programmers who think true values should be converted to 1? (Though even there, the longer version makes more sense in an assignment or return statement than in a conditional statement test.)


The construct if ((mask & FLAG3) == FLAG3) tests if all bits in FLAG3 are present in mask; if (mask & FLAG3) tests if any are present.

If you know FLAG3 has exactly 1 bit set, they are equivalent, but if you are potentially defining compound conditions, it can be clearer to get into the habit of explicitly testing for all bits, if that's what you mean.


When it is for a bitset, so you have to compare just a single bit, it is okay to have if(mask & value).

But, suppose that you have an IP address stored on ant int32 and you want to know whether it is 192.168.*, then you will have to do:

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


Your condition will be true if the result is non-zero. In your example, the result of both operations would be equivalent, and the second option could even be slightly faster because some CPUs can test for zero easier than other arbitrary numbers, BUT:

Obviously, you can't do the second option if the value you're checking for consists of more than one bit. In that case, you have to use the first option. That obviously also applies if you're checking for several bits at the same time.


Even for the single-bit value where these statements are actually equivalent, I always favour the explicit comparison.

  1. It makes the intent clearer. We really are interested in comparing flags. (x & Flag) == Flag is an established pattern and I can process and recognize it at the blink of an eye.

  2. I usually prefer explicit over implicit conversions. I make an exception for fail states (e.g. I write if (file) instead of if (file.good())) but when working with numbers, 0 is not a “fail state”, it’s a number like any others. I don’t like treating it differently in a boolean context.


if takes a boolean (bool). The former expression is directly of type bool, whereas the latter is a numeric value which will be implicitly converted to bool.


The first construct, if (mask & FLAG3) means "if at least one common bit is in the flag and mask". For example, if (formats & supported_formats) would be true if any bit were in common between formats and supported_formats.

The second construct, if (mask & FLAG3) == FLAG3 means "if all set bits in FLAG3 are set in the mask". For example, if (things_you_have & things_required) == things_required would be true if all things_required were in things_you_have.

Here's a quick hit of some special cases:

  • For FLAG_WITH_EXACTLY_ONE_BIT_SET, both cases work.
  • For OBSOLETE_FLAG_SET_TO_ZERO, the first case always returns false.
  • For FLAG_WITH_MULTIPLE_BITS_REQUIRED, or FLAG_WHICH_IS_REALLY_TWO_FLAGS_COMBINED_WITH_AN_OR, the first case returns true when it should not. The second case returns correctly.

If you have the case of a FLAG_WITH_EXACTLY_ONE_BIT_SET, you should code with the second construct to avoid strange problems when the flag value gets changed. Be explicit unless your profiler tells you to squeeze out every operation.

0

精彩评论

暂无评论...
验证码 换一张
取 消