Q: What is the right type to use for Boolean values in C? Is there a standard type? Should I use #defines or enums for the true and false values?
A: Traditionally, C did not provide a standard Boolean type, partly and partly to allow the programmer to make the appropriate space/time tradeoff. (Using an int may be faster, while using char may save data space. [footnote] Smaller types may make the generated code bigger or slower, though, if they require lots of conversions to and from int.)
However, C99 does define a standard Boolean type, as long as you include <stdbool.h>.
If you decide to define them yourself,
the choice between #defines
and enumeration constants
for the true/false values
is arbitrary and not
terribly interesting
(see also questions
2.22
and
17.10).
Use any of
#define TRUE 1 #define YES 1
#define FALSE 0 #define NO 0
enum bool {false, true}; enum bool {no, yes};
or use raw 1 and 0,
as long as you are consistent within one program or project.
(An enumeration may be preferable if your debugger
shows the names of enumeration constants
when examining variables.)
You may also want to use a typedef:
typedef int bool;
or
typedef char bool;
or
typedef enum {false, true} bool;
Some people prefer variants like
#define TRUE (1==1) #define FALSE (!TRUE)or define ``helper'' macros such as
#define Istrue(e) ((e) != 0)These don't buy anything (see question 9.2; see also questions 5.12 and 10.2).
Q: Isn't #defining TRUE to be 1 dangerous, since any nonzero value is considered ``true'' in C? What if a built-in logical or relational operator ``returns'' something other than 1?
A: It is true (sic) that any nonzero value is considered true in C, but this applies only ``on input'', i.e. where a Boolean value is expected. When a Boolean value is generated by a built-in operator such as ==, !=, and <=, it is guaranteed to be 1 or 0. Therefore, the test
if((a == b) == TRUE)would work as expected (as long as TRUE is 1), but it is obviously silly. In fact, explicit tests against TRUE and FALSE are generally inappropriate. In particular, and unlike the built-in operators, some library functions (notably isupper, isalpha, etc.) return, on success, a nonzero value which is not necessarily 1, so comparing their return values against a single value such as TRUE is quite risky and likely not to work.
(Besides, if you believe that
if((a == b) == TRUE)is an improvement over
if(a == b)why stop there? Why not use:
if(((a == b) == TRUE) == TRUE)or even:
if((((a == b) == TRUE) == TRUE) == TRUE)See also Lewis Carroll's essay ``What the Tortoise Said to Achilles.'')
Given that
if(a == b)is a perfectly legitimate conditional, so is
#include <ctype.h>
...
if(isupper(c))
{ ... }
since isupper is known to return zero/nonzero for false/true.
Similarly,
there should not be any reluctance to use code like
int is_vegetable; /* really a bool */
...
if(is_vegetable)
{ ... }
or
extern int fileexists(char *); /* returns true/false */
...
if(fileexists(outfile))
{ ... }
as long as is_vegetable and fileexists()
are of ``conceptual Boolean type.''
Alternatives like
if(is_vegetable == TRUE) or if(fileexists(outfile) == YES)are not really any improvement. (They can be thought of as ``safer'' or ``better style,'' but they can also be thought of as risky or poor style. They certainly don't read as smoothly. See question 17.10.)
A good rule of thumb is to use TRUE and FALSE (or the like) only for assignment to a Boolean variable or function parameter, or as the return value from a Boolean function, but never in a comparison.
See also question 5.3.
References:
K&R1 Sec. 2.6 p. 39, Sec. 2.7 p. 41
K&R2 Sec. 2.6 p. 42, Sec. 2.7 p. 44, Sec. A7.4.7 p. 204, Sec. A7.9 p. 206
ISO Sec. 6.3.3.3, Sec. 6.3.8, Sec. 6.3.9, Sec. 6.3.13, Sec. 6.3.14, Sec. 6.3.15, Sec. 6.6.4.1, Sec. 6.6.5
H&S Sec. 7.5.4 pp. 196-7, Sec. 7.6.4 pp. 207-8, Sec. 7.6.5 pp. 208-9, Sec. 7.7 pp. 217-8, Sec. 7.8 pp. 218-9, Sec. 8.5 pp. 238-9, Sec. 8.6 pp. 241-4
Lewis Carroll, ``What the Tortoise Said to Achilles''
Q: Is if(p), where p is a pointer, a valid and portable test?
A: Yes. See question 5.3.
Q: Should I use symbolic names like TRUE and FALSE for Boolean constants, or plain 1 and 0?
A: It's your choice. Preprocessor macros like TRUE and FALSE (and, of course, NULL) are used for code readability, not because the underlying values might ever change. It's a matter of style, not correctness, whether to use symbolic names or raw 1/0 values. (See also questions 5.10 and 17.10.)
On the one hand, using a symbolic name like TRUE or FALSE reminds the reader that a Boolean value is involved. On the other hand, Boolean values and definitions can evidently be confusing, and some programmers feel that TRUE and FALSE macros only compound the confusion. (See also question 5.9.)
Q: A third-party header file I just started using is defining its own TRUE and FALSE values incompatibly with the code I've already developed. What can I do?
A: See question 10.10.
Read sequentially: prev next up