Comparing a bit to a boolean
To convert any non-zero number to 1 (true), there is an old trick: apply the !
(not) operator twice.
if (!!(flags & AMAZING_FLAG) != doSet){
From a logical point of view, flags & AMAZING_FLAG
is only a bit operation masking all other flags. The result is a numerical value.
To receive to a boolean value, you would use a comparison
(flags & AMAZING_FLAG) == AMAZING_FLAG
and can now compare this logical value to doSet
.
if (((flags & AMAZING_FLAG) == AMAZING_FLAG) != doSet)
In C there may be abbreviations, because of the implicit conversion rules of numbers to boolean values. So you could also write
if (!(flags & AMAZING_FLAG) == doSet)
to write that more terse. But the former version is better in terms of readability.
You need to convert the bit mask to a boolean statement, which in C is equivalent to values 0
or 1
.
(flags & AMAZING_FLAG) != 0
. The most common way.!!(flags & AMAZING_FLAG)
. Somewhat common, also OK to use, but a bit cryptic.(bool)(flags & AMAZING_FLAG)
. Modern C way from C99 and beyond only.
Take any of the above alternatives, then compare it with your boolean using !=
or ==
.
You can create a mask based on doSet
value:
#define AMAZING_FLAG_IDX 1
#define AMAZING_FLAG (1u << AMAZING_FLAG_IDX)
...
uint16_t set_mask = doSet << AMAZING_FLAG_IDX;
Now your check can look like this:
setAmazingFlag(bool doSet)
{
const uint16_t set_mask = doSet << AMAZING_FLAG_IDX;
if (flags & set_mask) {
// Really expensive thing
// Update flags
}
}
On some architectures, !!
may be compiled to a branch and by this, you may have two branches:
- Normalisation by
!!(expr)
- Compare to
doSet
The advantage of my proposal is a guaranteed single branch.
Note: make sure you don't introduce undefined behaviour by shifting left by more than 30 (assuming integer is 32 bits). This can be easily achieved by a static_assert(AMAZING_FLAG_IDX < sizeof(int)*CHAR_BIT-1, "Invalid AMAZING_FLAG_IDX");