Introduction
Originally, C had no boolean type. Instead, int was invariably used such that 0 was treated as false and any non-zero value was treated as true. While this certainly worked, using int as a boolean has problems.
Problems with int
One problem with using int as a boolean is clarity. Consider the function:
int strbuf_reserve( strbut_f *sbuf, size_t res_len );
What does that function return? A simple boolean value? How many bytes were actually reserved? An error code? You have to read the documentation (if any) or the source code (if not — assuming you even have it) to know what the int means.
Consequently, many programmers, especially those who learned other languages first that had a boolean type (such as ALGOL, Fortran, or Pascal) often defined their own boolean “type” in C, something like:
#define bool int /* or: typedef int bool; */
#define false 0
#define true 1
or perhaps all-caps versions. However, that can cause its own problem. If you use a few C libraries from different authors in your program, each might define its own boolean type slightly differently that can lead to incompatibilities, warnings, or errors (depending on how each is defined).
Another problem with int as a boolean is that in structures, it takes up at least four times as much space as needed (assuming 32-bit integers).
Although a true boolean value needs only a single bit, it practically must be
sizeof(char)(which is always 1).
_Bool in C99
One of the jobs of a language standard committee is to standardize common industry practice to eliminate variances and incompatibilities. Eventually, the C Committee added a boolean type to C — sort of.
In C99, the C Committee finally (after 27 years) added a boolean type to C: _Bool. Why was it spelled like that? Why not simply bool? As I wrote in my book Why Learn C, §2.2, p. 29:
To evolve C, the C committee occasionally adds new keywords. The problem is that every new keyword has the potential to break existing programs because some may already use the same identifier. To help minimize this possibility, the committee decided that new keywords would generally start with an underscore followed by a capital letter (e.g.,
_Bool, §C.6), at least for a transition period to allow people time to update their programs. Such keywords may look odd, but it’s better than breaking programs.
However, the Committee did not add _False and _True keywords, so you still had to use 0 and non-zero. But they also added stdbool.h that did:
#define bool _Bool
#define false 0
#define true 1
so you could, at your option, #include that header and use the conventional names. This half measure worked well enough and, more importantly, didn’t break existing programs.
But when C11 with _Generic came out, _Bool didn’t play nice with it:
#include <stdbool.h>
void f_bool() { }
void f_int() { }
#define F(X) \
_Generic( (X), \
bool: f_bool, \
int : f_int \
)( (X) )
int main() {
bool b = false;
F( b ); // calls f_bool
F( false ); // calls f_int
}
The call of F passing false calls f_int because false is only a macro for 0 — which is an int.
Another difference between int and _Bool is what happens when certain values are cast:
int i1 = (int)0.5; // = 0 (truncation)
_Bool b1 = (_Bool)0.5; // = 1 (non-zero -> true)
int i2 = (int)LONG_MAX; // implementation defined
_Bool b2 = (_Bool)LONG_MAX; // = 1
Unlike int, the semantics of _Bool are more intuitive and always well defined, specifically, any non-zero value always gets implicitly converted to 1 (true).
bool in C23
In C23 the C Committee (after 51 years) added a complete boolean type to C: bool. Not only that, but false and true are finally keywords which means the problem with _Generic goes away.
Ideally, the C Committee should have added bool to C11 alongside _Generic — but better late than never.
Conclusion
Despite taking over a quarter of a century for _Bool and over half a century for bool, C finally has a proper boolean type that is clearer and smaller than int and is always well defined.
Top comments (0)