Kaiserludi
Kaiserludi

Reputation: 2472

Why are false and true defined as 0 and 1 in C99 and not as ((bool)0) and ((bool)1)?

I just stumbled across an assert that failed, as it compared false to the returntype of a function, as the function itself returned a bool and the assert checked not only the value, but also the type of the returnvalue to match the one of false, to guarantee, that a bool is returned.

Now the problem is that C99 defines bool as _Bool and _Bool is even not necessarily the same size as int (in fact, in my experience, on most platforms nowadays, it is often the same size as unsigned char), not to talk about being the same type (which is actually impossible, as _Bool is a builtin type of the language in C99), but defines false and true as 0 and 1 without any typecast and preprocessor definitions without a typecast will default to int.

If C99 would instead define false and true as ((bool)0) and ((bool)1), they would always be of type bool, no matter, how _Bool is defined.

So is there a good reason to have them always defined as ints, even when bool is not an int on that platform or is this just a bug in the language that should be fixed with C1x?

Upvotes: 5

Views: 7570

Answers (4)

Sander De Dycker
Sander De Dycker

Reputation: 16243

false and true are defined as the integer constants 0 and 1 respectively, because that's exactly what the C99 standard specifies in section 7.16 :

< SNIP >

The remaining three macros are suitable for use in #if preprocessing directives. They are

true

which expands to the integer constant 1,

false

which expands to the integer constant 0, and

< SNIP >

EDIT : as the comments below indicate, it seems I slightly misinterpreted the question, and I should have provided the reason the standard specifies it like that. One reason I can think of, is that true and false are supposed to be usable in #if preprocessing directives (as the quote from the standard mentions).

The reason ((bool) 0) or ((bool) 1) won't work in #if preprocessing directives, is because the standard doesn't allow it. In section 6.10.1 it says :

The expression that controls conditional inclusion shall be an integer constant expression except that: it shall not contain a cast;

Upvotes: 9

Rob Kennedy
Rob Kennedy

Reputation: 163257

All the other answers are trying to use the standard to justify why the standard defines things a certain way, which I find unsatisfactory. The standard defines not only the types, but also the operators and the preprocessor, so if C99 was introducing a Boolean type, why not change all the Boolean operators to evaluate to a value of that type and extend the preprocessor to support Boolean types?

To do so would be possible, but more complicated the necessary. It was far easier for the standard-writers and the compiler-writers to make only the minimum necessary changes to add a new Boolean type to the language. Since all the Boolean operations still evaluate to type int, all the pre-C99 compilers can be updated to support C99 without having to change their type-evaluation code for all the basic operators, and the standard-writers can be more confident that the new Boolean feature hasn't accidentally introduced inconsistencies to parts of the standard that had previously been fine. All they needed to do was make sure the "usual arithmetic conversions" applied to _Bool, and then everything else is guaranteed to work.

It's not a technical reason. It's a practical one.

Upvotes: 3

Stephen Canon
Stephen Canon

Reputation: 106127

Beyond the other reasons already mentioned, because a _Bool becomes an int anyway as soon as you do almost anything with it.

For example, what is the type of (_Bool)0 & (_Bool)1? You might think that the expression has type _Bool, but actually §6.5.10 defines the semantics of &:

... The usual arithmetic conversions are performed on the operands ...

"usual arithmetic conversions" has a very specific meaning in the C standard. It is defined in §6.3.1.8, and includes the following:

... the integer promotions are performed on both operands ...

"integer promotions" is also a defined term, from §6.3.1.1:

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.

Although narrower types than int exist in the C standard, they are automatically widened to int in nearly any expression. Together with the fact that the result of the boolean operations has type int, this makes int a natural choice for the type of these literals.

Upvotes: 5

kennytm
kennytm

Reputation: 523214

Firstly, although _Bool may not be int, it is required that a _Bool can accept the values 0 and 1, therefore expanding true and false to 1 and 0 are fine.

C99 §6.2.5/2: An object declared as type _Bool is large enough to store the values 0 and 1.

Also, for backward compatibility, true and false are reasonable to be ints, because all logical operators return int.

C99 §6.5.3.3/5: The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

C99 §6.5.8/6: Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false.90) The result has type int.

C99 §6.5.9/3: The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence.91) Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true.

C99 §6.5.13/3: The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

C99 §6.5.14/3: The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

And finally, as @Sander De Dycker mentioned, the standard defined true and false be expanded like that (C99 §7.16/3).

Upvotes: 2

Related Questions