Casting to _Bool

Viewed 75

Traditionally, Boolean values in C were represented with int or char. The new _Bool type makes intent clearer, but also has another interesting feature: it seems casting floating-point numbers to it, does not truncate toward zero, but compares with exact zero:

#include <stdio.h>

int main(int argc, char **argv) {
  double a = 0.1;
  int i = (int)a;
  printf("%d\n", i);
  _Bool b = (_Bool)a;
  printf("%d\n", b);
  return 0;
}

prints

0
1

So this is a semantic difference. And one I'm happy with; it duplicates the effect of using a floating-point number as a conditional.

Is this something that can be depended on across-the-board? Does the new C standard define the result of casting X to _Bool as identical to X ? 1 : 0 for all X for which that is a valid operation?

2 Answers

In the C Standard (6.3.1.2 Boolean type) there is written

1 When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1.

That is during conversion to the type _Bool the compiler does not try to represent the value (truncating toward zero or something else) of the operand of an expression with the casting operator as an integer. It only checks whether the value is equal or unequal to zero.

Actually this declaration

 _Bool b = (_Bool)a;

is equivalent to

 _Bool b = a;

It is entirely consistent, a non-zero value implicitly cast to _Bool is true. Since _Bool is a true Boolean type and not "faked", it can behave correctly. So:

_Bool b = (_Bool)a ;

is equivalent to:

_Bool b = (a == 0) ;

not:

_Bool b = ((int)a == 0) ;

In the end interpreting a float as Boolean is nonsense and ill-advised as is comparing it for equality to zero. If you want the semantic you expect, you must code it explicitly:

_Bool b = (_Bool)((int)a);

Semantically that is equivalent to :

_Bool b = (a < 1.0);

It is clearer and safer to use a Boolean expression than to force a value to Boolean with a cast.

Related