In Defense of the C99 Boolean Type

April 9, 2011 | Embedded Software

I really like a lot of the features in C99, including the new bool type. A lot of people have dismissed it as syntactic sugar or language bloat, but it does bring something new to the table.

First, how do you use bool? The best way is to include the stdbool.h header, which defines the bool type and the constants true and false as follows:

#define bool    _Bool
#define true 1
#define false 0

To maintain compatibility, the actual new keyword added to the language was _Bool. stdbool.h then defines a macro that allows you to use the slightly friendlier bool type. That way code that defines its own, incompatible bool type can continue to work by just not including stdbool.h.

So far, there's nothing special here. The real excitement is buried in the ISO C99 standard. Here's section 6.3.1.2 of the n1256 ISO committee draft (yes, I'm too cheap to shell out $40 for the offical version of the standard).

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

Exciting, isn't it? Before the days of C99, programmers would typically represent boolean values as an int. That would cause all kinds of problems such as:

if( somevalue == TRUE )
{
/* do something */
}

This would cause unexpected behavior because TRUE would typically be defined to be 1, but somevalue wasn't guaranteed to just be 0 or 1. Now, if somevalue is a C99 bool, there is that guarantee. Of course, the code above is still dumb because it's excessively verbose.

Another problem was packing "boolean" values into flags. To get around the problem of "booleans" not being limited to 0 and 1, you would end up writing code like

flags = (condition1 ? 1 : 0 ) << 1 | (condition2 ? 1 : 0 ) << 2 | (condition3 ? 1 : 0 ) << 3;

Now, if the three condition variables above all have type bool, you can make this much more compact:

flags = (condition1 << 1) | (condition2 << 2) | (condition3  << 3);

So, does this actually work? Let's give it a whirl! Here's a silly little test function.

#include <stdio.h>
#include <stdbool.h>

bool test( void )
{
return printf( "blah" );
}

Here's the disassembly of that function (compiled for ARM, because I hate reading x86 assembly language). Notice addresses 10 and 14. Address 10 subtracts 0 from r0 and stores the result in r0 (on ARM r0 holds the return value from a function, which is printf in this case). That's setting up a comparison to 0 for address 14, which sets r0 to 1 if the return value from printf was not zero. If the return value from printf was 0, then r0 already has 0 in it, so there's nothing to do (clever optimizer!). Of course, r0 then becomes the return value from the test function, so this does exactly what we expect: It returns 0 if printf returned a value of 0, and 1 otherwise.

 0:   e52de004    push    {lr}        ; (str lr, [sp, #-4]!)
4: e59f0018 ldr r0, [pc, #24] ; 24 <test+0x24>
8: e24dd004 sub sp, sp, #4 ; 0x4
c: ebfffffe bl 0 <printf>
10: e2500000 subs r0, r0, #0 ; 0x0
14: 13a00001 movne r0, #1 ; 0x1
18: e28dd004 add sp, sp, #4 ; 0x4
1c: e49de004 pop {lr} ; (ldr lr, [sp], #4)
20: e12fff1e bx lr

And there you have it. The bool type isn't the most ground-breaking feature in C, but it isn't completely useless either.