Using bitwise operators for Booleans in C++
||
and &&
are boolean operators and the built-in ones are guaranteed to return either true
or false
. Nothing else.
|
, &
and ^
are bitwise operators. When the domain of numbers you operate on is just 1 and 0, then they are exactly the same, but in cases where your booleans are not strictly 1 and 0 – as is the case with the C language – you may end up with some behavior you didn't want. For instance:
BOOL two = 2;
BOOL one = 1;
BOOL and = two & one; //and = 0
BOOL cand = two && one; //cand = 1
In C++, however, the bool
type is guaranteed to be only either a true
or a false
(which convert implicitly to respectively 1
and 0
), so it's less of a worry from this stance, but the fact that people aren't used to seeing such things in code makes a good argument for not doing it. Just say b = b && x
and be done with it.
Using bitwise & on boolean
You just shouldn't use a bitwise operator on Boolean values. Apparently the compiler promotes the output of funcReturningBool
or the variable flag
to a signed integer, and warns you of possible unexpected effects.
You should stick to Boolean operators. Had &&=
existed, you could have written flag &&= funcReturningBool();
. Instead, use flag = flag && funcReturningBool();
Boolean bitwise and logical operators
As noted in the comments, you should use logical operators when you're doing logic and bitwise operators when doing bitwise operations.
One of the main differences among these is that C++ will short-circuit the logical operations; meaning that it will stop evaluating the operands as soon as it's clear what the result of the operation is.
As an example, this code:
bool foo() {
std::puts("foo");
return true;
}
bool bar() {
std::puts("bar");
return true;
}
//...
auto const res = foo() || bar();
will only output:
foo
Function bar
won't be evaluated as, in this case, evaluating foo
is enough to know the result of expression foo() || bar()
is true
.
Absolute value abs(x) using bitwise operators and Boolean logic
Assuming 32-bit words, as stated in the question:
For negative x
, x >> 31
is implementation-defined in the C and C++ standards. The author of the code expects two’s complement integers and an arithmetic right-shift, in which x >> 31
produces all zero bits if the sign bit of x
is zero and all one bits if the sign bit is one.
Thus, if x
is positive or zero, y
is zero, and x + y
is x
, so (x + y) ^ y
is x
, which is the absolute value of x
.
If x
is negative, y
is all ones, which represents −1 in two’s complement. Then x + y
is x - 1
. Then XORing with all ones inverts all the bits. Inverting all the bits is equivalent to taking the two’s complement and subtracting one, and two’s complement is the method used to negate integers in two’s complement format. In other words, XORing q
with all ones gives -q - 1
. So x - 1
XORed with all ones produces -(x - 1) - 1
= -x + 1 - 1
= -x
, which is the absolute value of x
except when x
is the minimum possible value for the format (−2,147,483,648 for 32-bit two’s complement), in which case the absolute value (2,147,483,648) is too large to represent, and the resulting bit pattern is just the original x
.
Can you bitwise shift a bool in C++?
From Shift operators [expr.shift]
The operands shall be of integral or unscoped enumeration type and integral promotions are performed.
The type of the result is that of the promoted left operand
bool
is an integral type so the code is well formed (bool
is promoted to int
and result is an int
).
From [conv.prom], we show what integers the booleans get promoted to:
A prvalue of type
bool
can be converted to a prvalue of typeint
, withfalse
becoming zero and true becomingone
Afterwards, the shift behaves normally. (Thanks, @chris)
Can I use bitwise operators instead of logical ones?
One possible answer is: optimization. For example:
if ((age < 0) | (age > 100))
Let assume that age = -5
, no need to evaluate (age > 100)
since the first condition is satisfied (-5<0
). However, the previous code will do evaluate the (age > 100)
expression which is not necessary.
With:
if ((age < 0) || (age > 100))
Only the first part will be evaluated.
Note: As @Lundin mentioned in the comments, sometimes |
is faster than ||
due to the accuracy of branching for the second option (and the problem of mis-prediction). So in cases where the other expression is so inexpensive, the | option may be faster. So the only way to know in those cases is to benchmark the code on the target platform.
The most important answer is to avoid undefined behaviors and errors:
You may imagine this code:
int* int_ptr = nullptr;
if ((int_ptr != nullptr) & (*int_ptr == 5))
This code contains undefined behaviour. However, if you replace the &
with &&
, No undefined behaviour exists anymore.
Understanding bitwise XOR (^) with boolean variables
As bool
is a narrower type than an int
, both arguments are implicitly converted to an int
prior to the XOR being evaluated. true
assumes the value 1
, and false
assumes the value 0
.
If that result is non-zero then the if
body runs, and that happens if and only if body1awake
is not equal to body2awake
.
So perhaps the equivalent
if (body1awake != body2awake)
would have been better. If the author thinks their way is faster then they need a stern talking to with compiler optimisations and as-if rule being introduced into the conversation.
Related Topics
Link Errors Using <Filesystem> Members in C++17
Benefits of Header-Only Libraries
Best Method for Storing This Pointer for Use in Wndproc
Template Function as a Template Argument
How to Read Groups of Integers from a File, Line by Line in C++
Possible Problems with Nominmax on Visual C++
Correctly Reading a Utf-16 Text File into a String Without External Libraries
C++ Inherit from Multiple Base Classes with the Same Virtual Function Name
What's the Point of G++ -Wreorder
Is There Actually a Reason Why Overloaded && and || Don't Short Circuit
Linking to Msvc Dll from Mingw
How to Extract the Source Filename Without Path and Suffix at Compile Time