Menu

Booleans in C: stdbool.h, _Bool, and Truthiness

C had no boolean type until C99. Zero is false, everything else is true, comparisons yield int - and stdbool.h gives you bool, true, and false on top. Plus the = vs == bug this design enables.

This page includes runnable editors - edit, run, and see output instantly.

C spent its first 27 years without a boolean type. That is not an oversight - it is a design decision with consequences you meet on your first day, and one famous bug that follows directly from it.

Zero Is False, Everything Else Is True

There is no special true/false value in C's condition rules. if, while, for, &&, ||, and ! all ask exactly one question: is this value zero?

Negative numbers are true. Fractions are true. A non-null pointer is true. Only zero - in any type - is false.

This is why C code is full of idioms that look terse until you know the rule:

if (count)            /* if count is not zero */
if (!count)           /* if count is zero */
if (p)                /* if p is not NULL */
if (!strcmp(a, b))    /* if the strings are equal - strcmp returns 0 for a match */

That last one catches people. strcmp returns 0 when the strings match, so "equal" reads as "not" in an if. Writing if (strcmp(a, b) == 0) is clearer and does exactly the same thing.

Comparisons Produce int

A comparison in C is not a special kind of expression. It evaluates to an ordinary int with the value 1 or 0, and you can print it, store it, or do arithmetic with it:

The ! operator works the same way: it produces 1 if its operand is zero and 0 otherwise. So !!x is a classic idiom that normalizes any value to exactly 0 or 1.

bool, true, and false (C99)

C99 added a real boolean type called _Bool, and a header that gives it a readable name:

<stdbool.h> is tiny: it defines bool as _Bool, true as 1, and false as 0. That is the whole header. But using it makes intent visible in a way that int flag = 1; never does.

_Bool has one genuinely distinct behavior: it stores only 0 or 1. Assigning any non-zero value converts to exactly 1:

There is still no %b in printf for booleans - print them with %d, or convert to text yourself:

In C23 this got simpler still: bool, true, and false became real keywords, so the include is no longer required. Most code today still targets C17, so keep the #include <stdbool.h>.

Returning a Boolean From a Function

This is where bool earns its place most clearly:

A bool return type tells the caller what the value means. An int return type from a function called check_file could be a boolean, a count, or an error code - and in C library conventions it is often the third, where 0 means success. Naming the type removes the guess.

The = vs == Bug

Because assignment is an expression that yields the assigned value, and because any non-zero value is true, this compiles:

Two things went wrong at once. The condition assigned 5 to x, destroying its value, and then tested 5, which is non-zero, so the branch ran. The program has no error and no warning by default.

Worse, the version with 0 never runs its branch:

if (found = 0) { /* never taken - and found is now 0 */ }

Three defenses, in order of usefulness:

Compile with warnings. -Wall catches it:

warning: suggest parentheses around assignment used as truth value

Getting to zero warnings is the real fix here, and it costs one flag.

Write the constant first. The "Yoda condition" makes the typo a compile error:

if (5 == x)   /* correct */
if (5 = x)    /* error: not an lvalue - the compiler stops you */

Some teams love this and some find it unreadable; either position is defensible, but it does work.

Be deliberate when you mean it. Assignment inside a condition is genuinely useful for reading input:

int c;
while ((c = getchar()) != EOF) { ... }

The extra parentheses around c = getchar() are required for precedence, and they also signal that the assignment is intentional. That is the idiom - if your assignment-in-a-condition does not look like that, it is probably a typo.

Common Boolean Mistakes

Comparing to true. if (flag == true) works with stdbool.h, but it breaks the moment flag is an int holding 42, because 42 == 1 is false. Write if (flag).

Chained comparisons. if (0 < x < 10) is always true: 0 < x yields 0 or 1, and both are less than 10. Write if (x > 0 && x < 10).

Bitwise instead of logical. & and | are not && and ||. They do not short-circuit, and they combine bits:

Both operands are "true," and yet a & b is 0. Using & where you meant && produces a condition that is wrong only for certain values, which is the hardest kind of bug to find.

Comparing floats for equality. if (0.1 + 0.2 == 0.3) is false. Compare against a tolerance instead - see data types for why.

Frequently Asked Questions

Does C have a boolean type?

Since C99, yes: _Bool is a built-in type, and including <stdbool.h> gives you the friendlier spellings bool, true, and false. Before C99 there was no boolean at all - programs used int with 0 for false and 1 for true, which still works and is still common.

What counts as true in C?

Any non-zero value. 1, -5, 0.01, and a non-null pointer are all true in a condition; only 0, 0.0, and a null pointer are false. There is no separate boolean check - if (x) simply tests whether x is non-zero.

How do I use bool in C?

Add #include <stdbool.h> and then bool ready = true; works as you would expect. Under the hood bool is _Bool, which stores only 0 or 1 - assigning any non-zero value to it stores exactly 1.

What is the difference between = and == in C?

= assigns, == compares. if (x = 5) assigns 5 to x and then tests 5, which is non-zero, so the branch always runs. if (x == 5) tests equality. The first compiles without error, which is why -Wall and the habit of writing if (5 == x) both exist.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED