Reputation: 353
Given the following C11 code:
int a = 1234;
bool b = (bool)a; // equivalent to (a != 0) or (a != false) which evaluates to 1 or true
if (a) // equivalent to if(a != 0) or if (a != false) which evaluates to 1 or true
printf("a\n");
if (a == (bool)true) // should be equivalent to if(!(a == false)) or if (a != false)
printf("a == (bool)true\n");
I understand that true is #define true 1
but a bool
clearly is not an ordinary integral type because something like (bool)0.1
evaluates to 1 while a cast to int would result in 0.
1) Why wasn't true
defined as (bool)1
? This would allow the compiler to at least output a warning.
2) Why is the integer in my example not converted into a bool
such that a == (bool)true
would evaluate to (bool)a == (bool)true
which actually would be true?
Upvotes: 0
Views: 3871
Reputation: 153498
Why doesn't comparison with bool convert to bool in C11?
_Bool
is the lowest rank and equality operator ==
specifies that its _Bool
operands are promoted to int
. @StoryTeller
The rank of
_Bool
shall be less than the rank of all other standard integer types. C11 §6.3.1.1 1(Equality operators) If both of the operands have arithmetic type, the usual arithmetic conversions are performed. §6.5.9 4
(usual arithmetic conversions) ... the integer promotions are performed on both operands §6.3.1.8 1
(integer promotions) If an
int
can represent all values of the original type ... the value is converted to anint
... §6.3.1.1 2
OP's code samples did not have a "comparison with bool".
// int compared to int: false since a == 1234 and that is not equal 1
if (a == true)
Instead could have had
// int compared to _Bool: false since a == 1234 and that is not equal to 0 or 1
if (a == b)
With int == _Bool
, int == short
, int == signed char
, the same thing occurs. The lower rank operand is promoted to int
.
1) Why wasn't true defined as (bool)1? This would allow the compiler to at least output a warning.
Why? a standard committee decision of years ago. Considering true
as (int)1
rather than (_Bool)1
certainly would have impacted the existing code less when _Bool
was introduced. (C99). This is consistent with other sub-int
constants like SHRT_MAX
which is usually an int
, not short
. In any case, in most contexts, a promotion to int/unsigned
would occur anyway before further processing - like in this compare case.
Further (_Bool)1
is not needed to allow a compiler to provide a warning. A compiler can be made that supplies a warning using various analytic tools. As (_Bool)1
, it would simplify things for a compiler to provide such a warning though.
2) Why is the integer in my example not converted into a
bool
such thata == true
would evaluate to(bool)a == true
which actually would be true?
As true
is an (int)1
, with a == true
, both operands are int
. _Bool
does not apply here.
2) [OP Updated] Why is the integer in my example not converted into a
bool
such thata == true
would evaluate to(bool)a == true
which actually would be true?
The top of the answer addresses this: true
in an int
, so (bool)a
is promoted to an int
before the comparison as int
is higher rank than _Bool
.
Upvotes: 4
Reputation: 353
Summarizing from the comments:
_Bool
is actually "just" another unsigned integer type with the exceptional rule that conversions to it always result in 1 ("true") if the value does not equal 0 ("false").
Because it is an unsigned integer, integral promotion rules apply.
Even if true
was defined as (bool)1
the comparison a == true
results in actually comparing 1234 == 1
which is always false
.
Upvotes: -2
Reputation: 263267
I understand that true is
#define true 1
but abool
clearly is not an ordinary integral type because something like(bool)0.1
evaluates to 1 while a cast to int would result in 0.
bool
(actually _Bool
; bool
is a macro that expands to _Bool
) is an integer type. It does have a somewhat unusual feature that it doesn't share with any other type: converting any non-zero value to _Bool
yields 1
.
Note that the operators that yield logically Boolean values still yield an int
result with the value 0
or 1
. This generally isn't a problem due to implicit conversions.
1) Why wasn't
true
defined as(bool)1
? This would allow the compiler to at least output a warning.
Compilers are allowed to produce warnings whenever they like. A warning on a comparison to true
or false
would be a good idea.
2) Why is the integer in my example not converted into a
bool
such thata == true
would evaluate to(bool)a == true
which actually would be true?
a == true
has to convert its operands to the same type before it can compare them. This is done via the usual arithmetic conversions. The rules (which are fairly complex) are described in the N1570 section 6.3.1.8. A very quick and imprecise summary is that the operand of the narrower type (lesser integer conversion rank) is converted to the type of the other operand. For example, when you compare expressions of types int
and long
, the int
operand is promoted to long
. _Bool
is the narrowest integer type, so it's always promoted in a comparison unless it's being compared another _Bool
value.
Changing these rules just for _Bool
would be confusing, and it really wouldn't buy you much.
Bottom line: Don't compare values for equality to false
or true
. Don't write:
if (a == true)
just write:
if (a)
if that's what you mean. Similarly, don't write:
if (a == false)
just write
if (!a)
Upvotes: 2