108

Today while writing some Visual C++ code I have come across something which has surprised me. It seems C++ supports ++ (increment) for bool, but not -- (decrement). It this just a random decision, or there is some reason behind this?

This compiles:

static HMODULE hMod = NULL;
static bool once = false;
if (!once++)
    hMod = LoadLibrary("xxx");

This does not:

static HMODULE hMod = NULL;
static bool once = true;
if (once--)
    hMod = LoadLibrary("xxx");
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Suma
  • 33,181
  • 16
  • 123
  • 191
  • 2
    hm, same for xcode and gcc compiler – Vladimir Aug 10 '10 at 15:14
  • Yep, `++once` and `once++` work with gcc, but not the decrements. – Justin Ardini Aug 10 '10 at 15:16
  • Maybe retag "history" instead of "operator-keyword", so this is grouped with all the other fun explanations as to why various crazy things are reasonable if you consider the history? :) – Jon Hanna Aug 10 '10 at 15:52
  • Note as of C++17 the pre-increment operator for `bool` is deprecated, [souce](http://en.cppreference.com/w/cpp/language/operator_incdec). – cogle Feb 03 '18 at 07:20
  • 1
    this can be replaced with `std::exchange(once,false)` (note: *not* atomic), if you want something non-deprecated. – golvok Oct 17 '19 at 20:30

4 Answers4

97

It comes from the history of using integer values as booleans.

If x is an int, but I am using it as a boolean as per if(x)... then incrementing will mean that whatever its truth value before the operation, it will have a truth-value of true after it (barring overflow).

However, it's impossible to predict the result of -- given knowledge only of the truth value of x, as it could result in false (if the integral value is 1) or true (if the integral value is anything else - notably this includes 0 [false] and 2 or more [true]).

So as a short-hand ++ worked, and -- didn't.

++ is allowed on bools for compatibility with this, but its use is deprecated in the standard and it was removed in C++17.


This assumes that I only use x as an boolean, meaning that overflow can't happen until I've done ++ often enough to cause an overflow on it's own. Even with char as the type used and CHAR_BITS something low like 5, that's 32 times before this doesn't work any more (that's still argument enough for it being a bad practice, I'm not defending the practice, just explaining why it works) for a 32-bit int we of course would have to use ++ 2^32 times before this is an issue. With -- though it will only result in false if I started with a value of 1 for true, or started with 0 and used ++ precisely once before.

This is different if we start with a value that is just a few below 0. Indeed, in such a case we might want ++ to result in the false value eventually such as in:

int x = -5;
while(++x)
  doSomething(x);

However, this example treats x as an int everywhere except the conditional, so it's equivalent to:

int x = -5;
while(++x != 0)
  doSomething(x);

Which is different to only using x as a boolean.

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 1
    Thank you. Great to know I can still give answers people like on this, given how long it is since I've actually written a line of C++ :) – Jon Hanna Aug 10 '10 at 15:50
  • 8
    But if x were -1 (TRUE in some platforms like VB), ++x would be FALSE. – James Curran Aug 10 '10 at 15:51
  • 4
    @James, in C and C++ that would be the case I was thinking of when I said ("barring overflow"). Actually in VB any non-zero has truth value TRUE (like in C), but they have -1 rather than 1 as the result of true boolean operations as then NOT(TRUE) is FALSE, NOT(FALSE) is TRUE, x OR TRUE is TRUE, x OR FALSE is x, x AND FALSE is FALSE and x AND TRUE is x, etc using the same operators for boolean and bit-wise operations (since VB assumes twos-complement so -1 is all 1 bits). However, this can cause some strange bugs in VB if the coder doesn't catch that 2 (true) AND 4 (true) results in 0 (false). – Jon Hanna Aug 10 '10 at 16:04
  • This answer doesn't feel very satisfying, as half of all `int` values fail the `++ -> always true` test. If it was `unsigned int` on the other hand... – Izkata Mar 01 '14 at 23:27
  • @Izkata no, every `int` value but one passes it. `-1` fails, and the maximum `unsigned int` fails, but all others result in true. – Jon Hanna Mar 02 '14 at 00:20
  • @JonHanna All negatives would eventually fail in a loop, so it has the same predictability as `--` with all positives... – Izkata Mar 02 '14 at 02:42
  • @Izkata but with an integer being used solely as a bool, that won't happen until after overflow. As I say above, the overflow case is still a good reason to consider it bad practice, but that's a different matter to the fact that it was indeed used. – Jon Hanna Mar 02 '14 at 09:52
  • `CHAR_BIT` (not `CHAR_BITS`) is required to be least 8. – Keith Thompson May 15 '17 at 17:35
  • @KeithThompson I could be wrong, but I think it could be less prior to the 89 version. – Jon Hanna May 15 '17 at 21:26
  • 2
    @JonHanna: ANSI C89 was the first C standard. The ANSI C committee invented the `` header and the `CHAR_BIT` macro. Prior to that, I suppose there theoretically could have been implementations where `char` is narrower than 8 bits, but as far as I know there were none. In particular, K&R1 (published in 1978) lists 4 sample implementations, all of which have 8-bit or 9-bit `char`. – Keith Thompson May 15 '17 at 22:51
  • @KeithThompson machines with 5-bit bytes (or less) have been produced, though they would have already been old in 1989. A C implementation that didn't do something to have `char` different to the machine's byte size would hence have only 5 bits. It's a deliberately extreme example though. – Jon Hanna Feb 27 '18 at 11:07
  • 1
    @JonHanna: A conforming C implementation *must* have `CHAR_BIT >= 8`. The standard doesn't make allowances for targets where that's difficult. (You could have a non-conforming implementation, of course.) – Keith Thompson Feb 27 '18 at 16:34
  • 1
    @KeithThompson, or a pre-standard implementation. We are after all talking about something that isn't a good idea, but is supported because of the legacy of people doing it. – Jon Hanna Feb 27 '18 at 22:22
  • 1
    @JonHanna: Sure. A pre-standard implementation is almost by definition not conforming. – Keith Thompson Feb 27 '18 at 22:45
29

ANSI ISO IEC 14882 2003 (c++03):

5.2.6-2

The operand of postfix -- is decremented analogously to the postfix ++ operator, except that the operand shall not be of type bool. [Note: For prefix increment and decrement, see 5.3.2. ]

And unsurprisingly...

5.3.2-2

The operand of prefix -- is modified by subtracting 1. The operand shall not be of type bool. The requirements on the operand of prefix -- and the properties of its result are otherwise the same as those of prefix ++. [Note: For postfix increment and decrement, see 5.2.6. ]

Also the 5.6.2-1 and 5.3.2-1 mention that ++ for bools shall be true and Annex D-1 says that ++ on bools in deprecated.

Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83
11

Due to historical reasons this was supported. But note that ... The use of an operand of type bool with the ++ operator is deprecated see Section 5.3.2 in the C++ Standard(n3092)

5.3.2 Increment and decrement [expr.pre.incr]

  • The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated). The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a completely-defined object type. The result is the updated operand; it is an lvalue, and it is a bit-field if the operand is a bit-field. If x is not of type bool, the expression ++x is equivalent to x+=1 [ Note: see the discussions of addition (5.7) and assignment operators (5.17) for information on conversions. —end note ]
  • The operand of prefix -- is modified by subtracting 1. The operand shall not be of type bool. The requirements on the operand of prefix -- and the properties of its result are otherwise the same as those of prefix ++.
Abhay
  • 7,092
  • 3
  • 36
  • 50
3
  • With the old standards (C++98) it is not an error.
  • With the new standards incrementing a boolean is deprecated. (C++11)
  • You can use incrementation on a boolean until C++17.
mustafagonul
  • 1,139
  • 1
  • 15
  • 32