tags:

views:

484

answers:

9

C++ standard says in section 4.12,

An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false any other value is converted to true.

Which means that the following code is valid,

if(5)
  std::cout << "WOW!";

It is syntactically valid but semantically it doesn't make any sense. My question is why C++ is allowing such strange things? AFAIK, it is not making any advantage rather than making confusion.

+17  A: 

I think it's historical, and a by product of how C used to evaluate bool like concepts...

C didn't use to have a boolean type, and in the 'down to the metal' paradigm of C, pointers and numeric types, etc. that were set to NULL were also implicitly false.

If you think of it as 'nothing/zero == false' and 'anything else == true' it actually does make sense.

John Weldon
And the reason that C uses 0 == false, not 0 == true is that a processor doesn't really have any data types - just different size registers (if you're lucky). The 'boolean' operations supported by the hardware boil down to 0 or not zero in a register. C just made that visible to the programmer. Remember that C can be thought of as a high level assembly language and it makes perfect sense.
Michael Kohne
+7  A: 

Actually, in many languages, including C/Python/Perl/BASIC non-zero integer/pointer value is always considered true, 0 considered false.

This is known conventions in many programming languages, so there is no reason, why this shoudn't be in C++?

The question is why in Java this is not so?

Artyom
Probably to force the programmer to be explicit in the logical conditions and make code more readable.
quant_dev
+3  A: 

It's from product of C.

Note also, these are (logically if not computationally) equivalent:

if (x && y || z)

if (x * y + z)

(I know this because TI99/4a BASIC did not have AND nor OR operations, so * and + had to do double duty, and in TI99/4a BASIC, booleans worked as in C.

smcameron
Not so. If x == 1 and y == -1, then x || y is true, but x + y is false.
Steve Jessop
+1  A: 

It's an artifact of a specific hardware limitation.

The terms "int", "short", "bool", et. al. only have real differing semantic meaning as long as the compiler is working - at runtime, it's just a 1 word (8 bit) value, 2 word (16 bit) value, 4 word (32 bit) value, etc.

So the real question here isn't "why does C++ except 5 as a boolean value", but "why did C?" And the answer, is that due to memory alignment, it wasn't possible in all cases to store a single bit anywhere, so the compilers just used a whole word. The fact that there's a designated "bool" type in C++ is just some lexical hand waving.

Chris
A: 

This is conjecture, but I believe it's due to the fact that C was designed as a minimalist language.

First, boolean evaluation and arithmetic evaluation are so similar that they are actually combined in the C parser, which reduces the overall size of the parser - C++ inherited this.

Second, testing for a non-zero result in assembly is generally carried out using a single opcode that test a register for a zero value and if true, jumping to the 'else' part of the statement. If the value is non-zero, execution naturally flows on into the 'if-true' part of the statement.

IanM_Matrix1
A: 

Historically, C is a relatively Weakly Typed language, designed for simplicity and efficiency rather than robustness. Pascal and similar languages are more strongly typed - enums, pointers, ints and bools cannot be randomly mixed and matched in expressions.

C (and many C++) programmers have grown up with this background, and you'll often see idiomatic code like this:

while (1)
   dosomething(); // repeats forever

.. or...

char * pointer;

if (pointer)  // tests pointer for being != 0, which equals NULL.
  fred = *pointer;

Personally, despite using C/C++ for over 20 years, I still find this second idiom ugly, as it makes two "hidden" casts/assumptions in a single line - that (NULL == 0), and that (0==FALSE).

Roddy
+2  A: 

I think the reason is history. It may be worth to note that next C++ version (C++0x, C++1x) introduces scopes enumerations that are not allowed to implicitly convert to an integer, making the following code ill-formed

enum class X { A, B, C };
if(X::B) { ... }

It makes sense to me for numbers to allow the implicit conversion to bool, though, but it doesn't make much sense to me for enumerations, because the primary purpose is to enumerate a list of values - only secondary the real values of an enumerator are of interest most of the time, i believe. Scoped enumerations will require a cast

if(static_cast<bool>(X::B)) { ... }

This adds some type-safety that the needed C compatibility of enumerations did not allow so far (i guess this would break a lot of code if forbidden to ordinary enumerations).

Johannes Schaub - litb
A: 

I can't find the exact citation, but it was always said that C combined all the power and flexibility of assembly language with the safety and ease-of-use of assembly language.

Usually the processor has no boolean, integer, ptr types. They're all just numbers in memory or registers.

Personally I've always liked the idiom:

some_obj * thingy;
if (thingy) ...

It seems like a natural and concise way to express "thingy exists" or "is initialized". But then, I spent a lot of time in assembly language.

Although I do tend to use "thingy == null" (or nil) in Objective-C, Java, C#, because you just feel a little less sure what's going on in those languages, being further from the hardware. In some languages someone could even have overridden the "==" operator.

You could just think of "if (ptr)..." as calling an implicit "cast to boolean" operator...

effish
A: 

There are good answers there but I want to point out one more thing: even if you can't say boolean = number and boolean = pointer it still makes sense to have if(number) or if(pointer) constructions.

ilya n.