Skip to content

Latest commit

 

History

History
47 lines (39 loc) · 5.11 KB

raw_thoughts.md

File metadata and controls

47 lines (39 loc) · 5.11 KB

Avoid Bitwise Operations for Booleans

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 is false then the result of b && f2() will also be false regardless of f2(). That is why the call to f2() 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.