Say I have a set of flags, encoded in a uint16_t flags
. For example, AMAZING_FLAG = 0x02
.
Now, I have a function. This function needs to check if I want to change the flag, because if I want to do that, I need to write to flash. And that is expensive. Therefore, I want a check which tells me if flags & AMAZING_FLAG
is equal to doSet
. This is the first idea:
setAmazingFlag(bool doSet)
{
if ((flags & AMAZING_FLAG) != (doSet ? AMAZING_FLAG : 0)) {
// Really expensive thing
// Update flags
}
}
This is not an intuitive if statement. I feel like there should be a better way, something like:
if ((flags & AMAZING_FLAG) != doSet){
}
But this does not actually work, true
seems to be equal to 0x01
.
So, is there a neat way to compare a bit to a boolean?
Boolean values and operations Constant true is 1 and constant false is 0. It is considered good practice, though, to write true and false in your program for boolean values rather than 1 and 0.
You ask: “Is there any reason not to use the bitwise operators & , | , and ^ for "bool" values in C++? ” Yes, the logical operators, that is the built-in high level boolean operators ! , && and || , offer the following advantages: Guaranteed conversion of arguments to bool , i.e. to 0 and 1 ordinal value.
A variable of the primitive data type boolean can have two values: true and false (Boolean literals).
To convert any non-zero number to 1 (true), there is an old trick: apply the !
(not) operator twice.
if (!!(flags & AMAZING_FLAG) != doSet){
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 ==
.
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 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:
!!(expr)
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");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With