Sometimes I see code like this
bool b = f(); // Function `f` returs `bool`.
.. // Some code here.
b &= f2(); // Function `f2` returs `bool`.
The author wants something like this bool b = f() && f2()
, but some code needs to be executed between f()
and f2()
. The line with the operator &=
is equivalent to the line b = b & f2()
. Here the operator &
is bitwise and in general case is different from the logical operator &&
.
As long as in the fragments above the b
is correct bool
, f()
and f2()
return correct bool
, the behavior is likely to correspond to the author's expectation. But some programmers use the line with the operator &=
as a model, and they apply it for functions returning bool-like value, i.e. for functions that return 0
as an indication of false
, and an arbitrary non-zero value as an indication of true
.
Now imagine how the behavior of the line can change:
// Let's assume that by this moment `b` is `true` (1).
b &= f3(); // Function `f3()` returns `4` as an indication of `true`.
The line is equivalent to b = b & f3()
, which is equivalent to b = 1 & 4
, which results in a value of 0
(false
) saved in b
. To summarize, the author is trying to apply the AND operation to true
and true-like value 4
, expects true
as a result, but gets false
. The compiler will hardly warn.
To avoid problems use the logical operators instead, e.g. b = b && f2()
. The logical operators (&&
) require bool
operands (b
and value returned by f2()
). If any operand is not bool
then it will be converted to bool
according to the Boolean Conversion rules. And the result will correspond to the expectation.
Note
However the recommended logical operators still may not fully filter out the incorrect bool
values (not equal to false
and not equal to true
) shown in the section Know the Limitations of memset()
When Initializing. E.g.
b = b || f4(); // Function `f4()` returns an incorrect `bool` with value `0x0101`.
The compiler can still implement the logical operation ||
with the bitwise OR machine instruction applied to b
and value returned by f4()
, and save the result in b
, leading to an incorrect value 0x0101
in b
.
What To Remember
- Avoid bitwise operators for Booleans. Use logical operators instead. E.g.
b = b && f2()
. - Don't forget that the right-hand-side of the operator can be optimized out. E.g. if
b
isfalse
then the result ofb && f2()
will also befalse
regardless off2()
. That is why the call tof2()
can be skipped in some contexts (and in some contexts it will be skipped [to do]). See details in [MISRACpp2008] Rule 5–14–1 mentioned below.
How to Automate Catching This
The code analysis tools supporting the following checks should catch this issue.
- [MISRACpp2008] MISRA C++:2008 - Guidelines for the use of the C++ language in critical systems.
- Rule 4–5–1 (Required) Expressions with type bool shall not be used as operands to built-in operators other than the assignment operator =, the logical operators &&, ||, !, the equality operators == and !=, the unary & operator, and the conditional operator.
- [MISRAC2004] MISRA-C:2004. Guidelines for the use of the C language in critical systems.
- Rule 12.6 (advisory): The operands of logical operators (&&, || and !) should be effectively Boolean. Expressions that are effectively Boolean should not be used as operands to operators other than (&&, ||, !, =, ==, != and ?:).
See Also
- V564. The '&' or '|' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' or '||' operator (+RU).
- V792. The function located to the right of the '|' and '&' operators will be called regardless of the value of the left operand. Consider using '||' and '&&' instead (+RU).
- [MISRACpp2008] MISRA C++:2008 - Guidelines for the use of the C++ language in critical systems.
- Rule 5–0–20 (Required) Non-constant operands to a binary bitwise operator shall have the same underlying type.
- Rule 5–0–21 (Required) Bitwise operators shall only be applied to operands of unsigned underlying type.
- Rule 5–14–1 (Required) The right hand operand of a logical
&&
or||
operator shall not contain side effects.