Previous Table of Contents Next


The unary ! operator negates the truth of its (single) operand. The expression

!(a > b && c > d)

is true if it is not the case that a is greater than b and c is greater than d. (Logicians know that by applying De Morgan’s theorem, the preceding expression can be transformed to the equivalent a <= b || c <= d.)

The && and || operators have an additional property, known as “short circuiting.” If the left-hand side of the && operator is false, the result can never be true, so the right-hand side is not evaluated at all in that case. Similarly, if the left-hand side of the || operator is true, the result can never be false, so the right-hand side is not evaluated. Therefore, an expression like

n != 0 && sum/n > 0

is safe; if n is 0, no divide-by-0 will occur.

The precedence of the binary logical operators is lower than that of the relational operators; expressions like

a == 2 || a == 3

and

x > 0 && x < 10

are interpreted as

(a == 2) || (a == 3)

and

(x > 0) && (x < 10)

as you would expect. As is traditional in boolean algebra, the precedence of && is higher than ||, so

a > b || c > d && e > f

is interpreted as

a > b || (c > d && e > f)

As always, explicit parentheses can be used to force a particular interpretation. For example, a common idiom in C is

(c = getchar()) != EOF

which calls the function getchar, assigns its return value to the variable c, and also compares it to the constant EOF. Because the precedence of = is lower than !=, the parentheses are required to achieve the desired interpretation. (See section 3.3.9 for a complete precedence table.)

How does C represent true and false values? By definition, any value that is not equal to zero is true, whereas a value that compares equal to 0 is false. So the operation of the && operator can be paraphrased as “if the left-hand operand is not zero and the right-hand operand is not zero, return a nonzero result.”

Although any nonzero value is considered to be true, the operators of this section always generate the value 1 for truth. For example, the operation of &&, ||, and ! can be summarized in this truth table:

a b a && b a || b !a !b

0 0 0 0 1 1
0 nonzero 0 1 1 0
nonzero 0 0 1 0 1
nonzero nonzero 1 1 0 0

(Returning to a previous example, the incorrect expression

0 < x < 10

always yields true, regardless of the value of x, because it is interpreted as

(0 < x) < 10

The first < yields either 0 or 1, which is certainly less than 10.)

Because true and false are represented as zero and nonzero, it is possible to effectively store truth values in ordinary variables. Variables of several types may be chosen, although char and int are most popular. (C has no predefined bool type.) For example, having declared and initialized

int xbetween = (x > 0 && x < 10);

the variable xbetween now contains a nonzero value (specifically, 1) if x is between 0 and 10, and zero otherwise. (In the initialization, the parentheses are unnecessary, but are inserted for clarity.) Later, the variable xbetween could be used in a context in which a true/false value was expected:

if(xbetween)
    …

Furthermore, because the interpretation of true is simply “not equal to 0,” any value (whether it is thought of as being a true/false value) may be tested for zero/nonzero by placing it in a conditional context. If the variable nitems contains a number of items, the test

if(nitems) …

does something if nitems is not 0. An earlier example, which tested whether an average existed and was greater than zero (without ever dividing by zero), could have been written

n && sum/n > 0

Opinions differ on whether testing ordinary variables in this way is good style, but the idiom is often seen and must be recognized.

In summary: When a value is being tested for truth or falsehood, any nonzero value is considered true, but when an operator of this section generates a true value, it generates the value 1. However, many functions that conceptually return true/false values return true values other than 1, so it is never a good idea to test a conceptually boolean value for equality with the constant 1. That is, don’t write if(isalpha(c) == 1); write if (isalpha(c)) instead. (See section 3.10.3 for information on isalpha and related functions.)


Previous Table of Contents Next