In Defense of the C99 Boolean Type
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.