alfC
alfC

Reputation: 16310

Are bitwise and logical operations the same for bool type?

C++ has logical operations, !a, a && b, a || b applicable to true/false values. And it has bitwise operations, applicable to all (integer?) types, ~a, a & b, a | b, a ^ b, (a << N, a >> N). Together with in place mutation operators, a &= b, a |= b, a ^= b, (a <<= b, a >>= b).

What confuses me is that bitwise operations could be acting on bits of bool that are not at all part of the true/false value. Even doing unnecessary bit operations. I guess that last fact makes bitwise shifting undefined for bool and that makes me doubt whether all bitwise operations are valid at all.

So, are these equivalent for bool types? ~a == !a, a && b == a & b, a || b == a | b?

For some reason (won't question here) there is no "in-place" logical mutation operators (i.e. a &&= b, a ||= b).

This inspires these questions, are these other bitwise operations valid on bools themselves? are a &= b and a |= b always equivalent to a = a && b and a = a || b respectively?** (no "in-place" xor a = a ^ b?)

Some examples: https://godbolt.org/z/hcccG8c9o

Upvotes: 2

Views: 305

Answers (1)

user17732522
user17732522

Reputation: 76859

(For simplicity I will assume C++20, i.e. two's complement representation of integer types. What I am writing may technically not hold prior to C++20 for all theoretically possible conforming representations of integer types.)

What confuses me is that bitwise operations could be acting on bits of bool that are not at all part of the true/false value.

The built-in bitwise operations have the usual arithmetic conversions applied to their operands first. For integral operands that implies integral promotions: Operands with a conversion rank below that of int are converted to int first (or unsigned int or a higher rank integral type if int can't hold all values of the original type).

The promotion always leaves the original value unchanged. In the case of bool, true is mapped to 1 and false to 0. So the result after promotion will have its least significant bit either set or unset, while all other bits are unset. Also, there are always at least 15 such bits, because int must be at least 16 bit wide.

As a consequence ~a == !a is always false. ~ will set these additional bits, while promotion of !a will not. However bool(~a) == bool(!a) is true only if a is false, because with additional bits set bool(~a) is always true.

a && b == a & b is always true, because additional bits will be zero when & is applied.

a || b == a | b is always true, because additional bits will again remain zero.

However, if a and b are actual expressions, then there is another difference in that the logical operators short-circuit evaluation, while the bitwise ones don't. Therefore, the side effects may be different.

Also, the result of the logical operators will be a bool, while that of the bitwise ones will be a int. Therefore they are not interchangeable as they might e.g. affect overload resolution where their result is used.

Also, this applies only for the built-in operators. If any overloaded operators are involved, nothing is guaranteed.

Upvotes: 5

Related Questions