views:

340

answers:

7

Is the following piece of code supposed to work?

bool b1 = true;
bool b2 = 1 < 2;
if (b1 == b2)
{
// do something
}

I suspect that not all 'trues' are equal.

+13  A: 

Yes. All trues are equal.

Daniel Daranas
Well, they're equal as far as `==` is concerned. Unless the programmer did something like override `operator==` to always return `false`. Since nothing in the question is an object, this won't be the case.
Mike D.
@Mike D. Even if we had objects, overriding operator== so that it always returns false does not seem a very intuitive technique to me.
Daniel Daranas
I'll raise the bar on this answer: all falses are equally false.
Hans Passant
@nobugz In fact, you lowered the bar. Because falses have been always equal, even in C.
danatel
@nobugz The complete rule would be: "All trues are equal. All falses are equal. All trues are equally true. All falses are equally false. Finally, true is different from false."
Daniel Daranas
@danatel: I disagree. He raised the bar in that he added information to my answer. C is a different language.
Daniel Daranas
@danatel: I don't think `(void *) 0`, `0`, and `0.0` are all equal, but they're all false in C.
David Thornley
@Daniel: I know that, but I've seen enough abuses of operator overloading that I can appreciate (yet not agree with) those who prefer to ban operator overloading. Personally, I use the `complex` template a lot, so I'd prefer to keep it.
Mike D.
+1  A: 

In C with ints you might have a point (although even there I think this particular sequence would be OK). In C++, yes this is safe.

T.E.D.
+6  A: 

Yes, as others have said bools can be compared for equality in C++. You may be thinking of things you heard from C. Since C has no bool type, booleans are represented as integers. In a boolean context any non-zero integer is true. However, they might have different bit patterns and thus not be equal. So the rule in C was not to compare 'booleans'.

Edit: per comments, C99 has a bool type. However the point of the answer was to indicate why the idea of not comparing bools is floating around. It is based on the long history of C, prior to C99.

Steve Fallows
Negative. C99 introduced #include <stdbool.h> http://en.wikipedia.org/wiki/Stdbool.h and true == (bool)3 in C when this is included.
Notinlist
@Notinlist: Sure, and you have to be using C99 with a special header to have a real bool type. It's a step forward, but not completely.
David Thornley
+5  A: 

Yes, boolean values can only store true or false, and you can compare the values for equality.

However, some bad uses of bool variables can lead to "undefined" behaviours and might look as if it is neither true nor false. For example reading the value of an uninitialized automatic variable or direct memory copy from integers.

Take a look at the following (bad) example:

  bool b1 = true; 
  bool b2 = true; 
  *((char*)&b1) = 3;

  if( b1 ) cout << "b1 is true" << endl;
  if( b2 ) cout << "b2 is true" << endl;
  if (b1 != b2) cout << "b2 is not equal to b1" << endl;

On Visual Studio 9, it shows:

b1 is true

b2 is true

b2 is not equal to b1

Probably, because the compiler has directly compare the values stored.

J. Calleja
I can't imagine someone ever contorting the language in the way you have in line 3. That's a bizarre statement. Not that your point is any less valid...
Eric
Technically, the undefined behaviour comes from bad use of a cast, not of a boolean.
Mike Seymour
@Eric: Yes, I agree that line 3 is not "real code". It was a short example to demonstrate that the sentence: "not all 'trues' are equal" can be true.
J. Calleja
A: 

The problems are only when you get used to non-zero being true and forget that not all non-zeros are equal.

Imagine this:

You have a function keyPressed() that returns 0 on no key pressed, number of key when a key is pressed.

You wrote a simple switch in a loop:

if(keyPressed() && allow)
...

Now your company introduces normally open triggers in the devices and you need a pref.

bool key_switches_on = getPref("KeySwitchesOn");

if((keyPressed() && allow) == key_switches_on)
...

Then you notice "allow" is placed wrong...

if((keyPressed() == key_switches_on) && allow)

and suddenly only key number 1 works.

SF.
+1  A: 

When you assign an integral value to a boolean object (or initialize boolean object with an integral value) it is implicitly converted to a true or false by a standard boolean conversion (4.12). So, from the language point of view, your 1 and 2 are gone without a trace long before you even do the comparison. They both have become the very same true. There's no "all trues are equal" issue here. There's only one true.

Of course, some compiler might probably take a "lazy" approach and keep multiple different "trues" around, making sure that they "all are equal" at the moment of comparison and such, but I doubt this is a reasonable/viable approach.

In other words, in a reasonable implementation you should expect not only your comparison to hold true, but a much stronger comparison to be true as well:

bool b1 = true; 
bool b2 = 1 < 2;
if (memcmp(&b1, &b2, sizeof(bool)) == 0) {
  /* We should get in here */
}

This is not guaranteed by the language, but in real life it does describe the physical side of the situation quite well.

AndreyT
+1  A: 

In C++, bool is its own type, with the two possible values true and false. All comparisons will go as you expect. All true boolean values are the same thing, and the same with all false. It is true that not all expressions you can evaluate to true or false are the same.

In C89, to go back as far as I want to, any zero value (of any pointer or numeric type) is false, and anything else is true. This means that true values aren't necessarily equal to each other. 1 and 2 are true values, but 1 != 2, and 1 & 2 evaluates to 0, which is false.

It's also possible for C89 false values to not compare equal, although they will on every implementation I've ever used. A null pointer value is a constant integral zero cast to a pointer value. It is possible for a non-constant value 0 cast to a pointer value to not be a null pointer (and there have been systems where null pointers were not all bits 0). Therefore, (void *)0 is a null pointer value, and hence false, but int i;...i = 0;...(void *)i could possibly not be a null pointer value, and hence not false.

However, in C89, all operations that intend to return a boolean value (like && or ==, for example), will return 1 or 0, so that (1 == 3) == (4 ==3).

David Thornley