9. Boolean Expressions and Variables

comp.lang.c FAQ list · Question 9.1

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).


comp.lang.c FAQ list · Question 9.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''




comp.lang.c FAQ list · Question 9.3

Q: Is if(p), where p is a pointer, a valid and portable test?


A: Yes. See question 5.3.




comp.lang.c FAQ list · Question 9.4

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.)




comp.lang.c FAQ list · Question 9.5

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



about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North