15

I'm using someone else's code that was written with an older compiler that mapped a special BOOL type to an unsigned int, but in my compiler it's mapped to a true bool. In some places in his code he uses the bitwise shift operator << on the bool type, which I had never seen before and my compiler surprised me when it didn't complain.

Is that valid C++? Does the bool automatically get promoted to an int or uint?

I saw this related question, which provided some clarity on another issue, but it doesn't address the shift operators.

Phlucious
  • 3,704
  • 28
  • 61
  • Without trawling through standardese, you can see how the operators work with a [reference](http://en.cppreference.com/w/cpp/language/operator_arithmetic). – chris Nov 22 '17 at 16:32
  • I've seen bitwise shift before and understand its use... I'd just never seen it used with a `bool` type. I know my compiler allows it, but will others? That's what I want to know. – Phlucious Nov 22 '17 at 16:40
  • What should a bitshift on a bool do logically? –  Nov 22 '17 at 16:46
  • @manni66 My concern was that a bitshift of `true << N` would simply toggle the bool `N` times on some compilers. If N=5 that would have resulted in a value of false instead of 32. See https://stackoverflow.com/a/4330321/1666676 – Phlucious Nov 22 '17 at 16:50
  • Regarless of whether it's valid C++, it seems like an invalid _idea_ to call something `BOOL` if you're going to treat it like a bit array. – Solomon Slow Nov 22 '17 at 16:56
  • @jameslarge Exactly my line of thinking, though I think he's packing bool values into a bit array, which I suppose is why this might be expected behavior. – Phlucious Nov 22 '17 at 16:58
  • @Phlucious Then he shouldn’t be defining it to be equivalent to `bool`. – Daniel H Nov 22 '17 at 17:15
  • Why would you want to bitshift a bool - surely it's either true or false. Use an int instead ? – avrono Nov 22 '17 at 17:25

3 Answers3

12

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 type int, with false becoming zero and true becoming one

Afterwards, the shift behaves normally. (Thanks, @chris)

AndyG
  • 39,700
  • 8
  • 109
  • 143
  • 1
    The value follows usual bool-int conversions. `false` is converted to 0 and vice-versa, while `true` is converted to 1 and anything but 0 is converted to `true`. At that point, it's a regular shift on an `int`, with conversions to and from `bool` before and after the shift. – chris Nov 22 '17 at 16:36
  • @chris: Thanks. Updated. – AndyG Nov 22 '17 at 16:40
  • Thanks for clarifying that it's intended behavior. Can you update those citations to links? I don't understand the [foo.bar] syntax. – Phlucious Nov 22 '17 at 16:44
  • 1
    @Phlucious: I'm citing the standard document. I think there's an online draft somewhere I can point at. One sec. – AndyG Nov 22 '17 at 16:45
  • @Phlucious: Updated to links. – AndyG Nov 22 '17 at 16:48
  • I think it might be bettor to base the links on https://timsong-cpp.github.io/cppwp/n4659 (C++17 minus some editorial changes) instead of http://eel.is/c++draft/ (latest standard, which is “an early draft [which is] known to be incomplet, incorrekt, and has lots of **bad** *formatt* `ing`.”) – Daniel H Nov 22 '17 at 17:20
  • and could `int` get demoted to `bool`. – rsonx Feb 15 '21 at 05:48
1

It is worth to add some explanation on what others have pointed out: Bitwise shifting a bool is casted into int.

bool b = true;
bool d = b << 1;
printf("%d\n", d);

This code snippet prints 1 on the screen not 0. The reasoning is that b << 1 is casted to int which is 2 (binary 10). The result is then casted to bool. The latter casting would be 0 if the value of the int is 0 and 1 otherwise. Since the value of the int is 2, d stores 1.

The right way of shifting a bool is to use it with a bitwise AND (&) with true (1).

bool d = (b << 1) & 1;

This AND operation forces the left side to be casted as a bool.

0

The result type of shifting a bool is always int, regardless of what's on the right hand side.

Mosè Raguzzini
  • 15,399
  • 1
  • 31
  • 43