Logical operations in C

Since the 1999 version of the standard, C has had a bool datatype for representing true and false values. Before then, and sometimes still, you’ll see people use other types, and the language allows almost any value to be used to represent truth using the following simple rule.

So, the following would print its message.

if (17)
    puts("hello, world");

On the other hand, the following would not print anything.

if (0.0)
    puts("hello, world");

Sometimes programmers rely on anything not equal to zero being true; for example, you’ll sometimes see tests against zero abbreviated.

if (size != 0)
    puts("the thing isn't empty");

/* or, equivalently... */

if (size)
    puts("the thing isn't empty");

However, when somebody is explicitly trying to write a value intended to be true, they will always use 1, or the special constant true, which is just a fancy way of writing 1 when that would be clearer.

To have access to true, false, and the bool datatype, you must include the <stdbool.h> header. A bool variable is more clear than using some other type such as int when what you mean is to store a truth value, and it is likely smaller as well. A value of any other type, when stored into a bool, will be converted to 0 or 1 according to the truthiness rule above.

The important Boolean operators are all defined at a logical level. The AND operator is &&, the OR operator is ||, and the NOT operator is !.

bool a = false;
bool b = true;

bool x = a && b;  /* both a AND b */
bool y = a || b;  /* either a OR b */
bool z = !a;      /* NOT a, the opposite */

There is no logical XOR operator, unless you remember that equality and inequality are Boolean operators.

bool x = a == b;  /* a equals b */
bool y = a != b;  /* a and b differ, i.e. a XOR b */

There is one important caveat to using == and != in this way. The operands to &&, ||, and ! are converted to bool, so anything that isn’t 0 will count as 1. That’s obviously not true for == and !=, so some values that count as both true still don’t count as equal to each other. This isn’t an issue if you make sure the operands are bool.

The null pointer compares equal to zero, so it counts as false, and all pointers that could point to a valid object aren’t zero, so they count as true.

int x = 10;
int *px = &x;
int *pn = NULL;

if (px)
    puts("px points to something");
if (!pn)
    puts("pn is a null pointer");

The logical AND and OR operators are ‘short-circuiting’, meaning that as soon as it is possible to know what the result will be, they don’t bother evaluating any further. Note that true || x is going to result in true, regardless of the value of x. Similarly, false && y is going to result in false, regardless of y. This can be used to make a simple kind of conditional execution, and is most commonly seen protecting tests that could have undefined behavior otherwise.

/* does px point to an integer storing 10? */
if (px && *px == 10)
    puts("px points to something, and that something is 10");

/* looks similar, but has undefined behavior */
if (*px == 10 && px)

If px is a null pointer, dereferencing it to check whether its target is 10 has undefined behavior, likely a crash. The first example checks whether px is a non-null pointer, and then only if it is does the dereferencing happen. The second example always triggers that potentially undefined behavior, and then only if it survives does it check whether it would have been okay. In Boolean algebra i.e. math, the order of the operands to AND and OR doesn’t matter—they’re both commutative operators. In C it can matter, in case evaluating one of the operands is much slower or not necessarily safe.

You have attempted of activities on this page