Using strongly-typed Booleans in C and C++
One of the glaring omissions from the original C language was provision of a Boolean type. Booleans in C are represented by integers, with false being represented as zero and true being represented as 1. When an integer value is used as a condition, all nonzero values are intrepreted as true.
Strong typing is a valuable asset when writing code – whether critical or not – because type checks can and do uncover errors. So how can we use strongly-typed Booleans in C and C++?
If you choose to write in a limited subset of C++ rather than C (as I have advocated in previous posts) then you are halfway there already. C++ provides a built-in bool type with values false and true. Unfortunately, there are implicit type conversions between integral types and bool in both directions, and also from pointer and enumeration types to bool. But these conversions are easily uncovered by static checking. So, in the eCv processor, we insist that all such conversions are done explicitly with static_cast. This is a stronger requirement than the MISRA C++ rules.
What if you are writing in C and can’t easily make the transition to C++? One possibility is to use C’99 rather than C’90, because C’99 does provide a Boolean type. But C’99 compilers are not widely available.
Fortunately, it’s possible to use strongly-typed Booleans in C’90 too. We’ve written the eCv processor so that when it is run on C’90 source, it applies exactly the same rules as it does on C++ source. The eCv keyword bool is assumed to be a primitive type, with values false and true. Relational operators are assumed to yield bool, so are && and ||. Operands of && and || are required to have type bool, and so are the conditions in if statements, loop statements and conditional expressions.
When the source is not being processed by eCv, the following declaration is made visible in ecv.h:
typedef enum _bool { false = 0, true = 1 } bool;
so the code compiles as normal. In practice, we usually find that clients already have their own macro or type definitions to express Booleans; so the actual mechanism we provide is a little more complicated in order to accommodate those definitions.