3

If the _Bool type acts like an integer and doesn't enforce that a value is true/false or 1/0, for example:

_Bool bools[] = {0,3,'c',0x17};
printf("%d", bools[2]);

> 1

What is the advantage of having that there? Is it just a simple way to coerce things to see how they would evaluate for 'truth-ness', for example:

printf("%d\n", (_Bool) 3);
> 1

Or how is this helpful or useful in the C language?

David542
  • 104,438
  • 178
  • 489
  • 842
  • 3
    As far as I know you're not supposed to use it with the prefix, that's an implementation detail. Use `bool`. – tadman Jan 10 '21 at 05:34
  • 4
    @tadman C language, since C99 has `_Bool`. `bool` is defined as macro for `_Bool` in ``. – chux - Reinstate Monica Jan 10 '21 at 06:42
  • @chux-ReinstateMonica Sure, but that doesn't mean using literal `_Bool` is a good plan. That's a work-around to help people adjust to the "new" standard. Hopefully 21 years later people are ready. – tadman Jan 10 '21 at 08:29
  • 3
    @tadman `_Bool` isn't an implementation detail. It's a part of the standard interface. – Aykhan Hagverdili Jan 10 '21 at 09:00
  • @AyxanHaqverdili This was, as far as I understand, a way to avoid introducing a "breaking" change in C by declaring a new keyword. It's not something you'd want to deliberately use. It's a standardized thing, but it's also an "internal" inasfar as you using it directly is unusual. – tadman Jan 10 '21 at 09:21

3 Answers3

5

What advantage does _Bool give?

  1. The value of a _Bool is either 0 or 1. Nothing else, unlike an int.

  2. Conversion to a _Bool always converts non-zero to 1 and only 0 to 0.

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

Examples:

#include <math.h>
#include <stdlib.h>
_Bool all_false[] = { 0, 0.0, -0.0, NULL };
_Bool all_true[] = { 13, 0.1, 42.0, "Hello", NAN };

Notice the difference of conversion/casting to int vs; _Bool: (int) 0.1 --> 0, yet (_Bool) 0.1 --> 1.

Notice the difference of conversion/casting to unsigned vs; _Bool: (unsigned) 0x100000000 --> 0, yet (_Bool) 0x100000000 --> 1.

  1. _Bool adds clarity to boolean operations.

  2. _Bool is a distinctive type from int, char, etc. when used with _Generic.

  3. Prior to C99, C lacked _Bool. Much early code formed their own types bool, Bool, boolean, bool8, bool_t, .... Creating a new type _Bool brought uniformity to this common, yet non-uniform practice. <stdbool.h> is available to use bool, true, false. This allows older code, which does not include <stdbool.h> to not break, yet newer code to use cleaner names.


OP's example with "doesn't enforce that a value is true/false or 1/0" does enforce that bools[2] had a value of 1. It did not enforce that the initializer of 'c', an int, had to be in the range of [0...1] nor of type _Bool, much like int x = 12.345; is allowed. In both cases, a conversion occurred. Although the 2nd often generates a warning.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • thanks, could you please explain why `(unsigned) 0x1 0000 0000` would go to 0? isn't unsigned 4 bytes by default? – David542 Jan 10 '21 at 07:07
  • 1
    @David542 `unsigned` is specified as _at least_ 16-bit. It is commonly 32-bit. `0x1 0000 0000` is a 33 bit value. Casting that to a 32 or 16 bit `unsigned` narrows its value. In effect lopping off the lead `1`, leaving 0. Casting/converting `0x1 0000 0000` to `_Bool` is 1. – chux - Reinstate Monica Jan 10 '21 at 07:10
  • sorry I misread that. I saw the 9 0/1's and thought boolean but now I see the `0x` prefix. Thanks for pointing that out. – David542 Jan 10 '21 at 07:22
  • @David542 The absence of a Boolean type was deemed a short-coming of C. C99 added it and is generally well received. A singular aspect of `_Bool` I do not like is its size is not specified as 1. It is often 1 or sometimes the same size as `int`. I have never seen any other size for `_Bool`. – chux - Reinstate Monica Jan 10 '21 at 07:27
  • 1
    It's a bit weird that logical expressions evaluate to `int` and not `_Bool`. So `a != b` is an `int`. That could possibly matter for `_Generic`. – Aykhan Hagverdili Jan 10 '21 at 09:04
  • @AyxanHaqverdili True, logical expressions evaluation to `int` is a historic design choice made before `_Bool` existed and left _as is_ with `_Bool`'s introduction. – chux - Reinstate Monica Jan 10 '21 at 18:13
2

The advantage is legibility, nothing more. For example:

bool rb() {
  if (cond && f(y)) {
    return true;
  }

  return false;
}

Versus:

int rb() {
  if (cond && f(y)) {
    return 1;
  }

  return 0;
}

There's really no other benefit to it. For those that are used to working in C code without bool, it's largely cosmetic, but for those used to C++ and its bool it may make coding feel more consistent.

As always, an easy way to "cast to a boolean value" is just double negation, like:

!!3

Where that will reduce it to a 0 or 1 value.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • What’s the `sizeof(bool)` compared to `sizeof(int)` though? And does C permit bitfield packing such that `sizeof(bool[8]) == sizeof(char)`? – Dai Jan 10 '21 at 05:37
  • I'm not sure of any C implementation that does the packing like C++ does with `std::vector` specialization. It seems like it just uses the [smallest convenient unit](https://stackoverflow.com/questions/8014161/in-c-how-much-space-does-a-bool-boolean-take-up-is-it-1-bit-1-byte-or-someth) that can hold a `0` or `1` value, which in most cases is a byte. If you had some oddball machine with a 4-bit word size, it'd be one of those instead. – tadman Jan 10 '21 at 05:38
  • @tadman what's considered better practice for 'cast to boolean' -- doing `(bool) val` or `!!val` ? – David542 Jan 10 '21 at 05:39
  • It really depends if you even need to in the first place, but if you must, then double negation usually does the job, though you don't see that nearly as much in C code as you do in things like Ruby and JavaScript where their boolean types are more formally expressed. – tadman Jan 10 '21 at 05:40
  • There is no need to cast to `bool` and the `!!val` trick is ugly and mildly confusing. Better express what you really want to say `val != 0`. – koder Jan 10 '21 at 11:16
1

Consider this:

(bool) 0.5 -> 1
( int) 0.5 -> 0

As you can see, _Bool does not act like an integer.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11