Logical Operators
Logical operators combine or invert boolean-style expressions. C provides three:
&& (logical AND), || (logical OR), and ! (logical NOT). They are used constantly in if conditions and loop guards to build compound tests out of simpler ones.Operator | Meaning | Result |
|---|---|---|
| Logical AND | true only if both a and b are true |
| Logical OR | true if at least one of a, b is true |
| Logical NOT | true if a is false, and vice versa |
Truthiness in C
Zero is false, everything else is true
Classic C has no dedicated boolean type. Any expression used where a condition is expected is treated as false if it equals zero, and true otherwise — this includes negative numbers, which are truthy. Logical operators themselves always produce
1 or 0 as an int.C
#include <stdio.h>
int main(void) {
int a = 5, b = 0;
printf("%d\n", a && b); // 0 — b is falsy
printf("%d\n", a || b); // 1 — a is truthy
printf("%d\n", !b); // 1 — NOT of 0 is 1
printf("%d\n", !a); // 0 — NOT of a nonzero value is 0
return 0;
}Short-Circuit Evaluation
Both
&& and || stop evaluating as soon as the overall result is known. For &&, if the left operand is false, the right operand is never evaluated (since the whole expression must be false). For ||, if the left operand is true, the right operand is never evaluated. This is not just an optimization — code intentionally relies on it, for example to guard against invalid memory access.C
#include <stdio.h>
int divisor = 0;
int isPositive(int n) {
printf("isPositive called with %d\n", n);
return n > 0;
}
int main(void) {
/* Guard pattern: only dereference/divide if the left side allows it. */
if (divisor != 0 && 100 / divisor > 1) {
printf("division happened\n");
} else {
printf("skipped the division safely\n");
}
/* isPositive() is never called because the left side is already true. */
if (1 || isPositive(-5)) {
printf("short-circuited || — isPositive was NOT called\n");
}
return 0;
}Logical vs Bitwise Operators
&& / || are not the same as & / |
This is one of the most common beginner mistakes in C specifically, because both the logical and bitwise operators exist and look almost identical.
&& and || operate on the truthiness of whole expressions and short-circuit. & and | operate bit-by-bit on the binary representation of integers and always evaluate both operands. Using a single & where you meant && usually still compiles — it just silently produces the wrong answer.C
int a = 2; // binary 010
int b = 4; // binary 100
printf("%d\n", a && b); // 1 — both are nonzero, so logically true
printf("%d\n", a & b); // 0 — bitwise AND of 010 and 100 has no shared bits
int x = 5, y = 0;
if (x & y) {
printf("won't print — bitwise AND, and y contributes no bits\n");
}
if (x && y) {
printf("also won't print — y is falsy\n");
}&&,||,!are the three logical operators; results are always1or0Zero is false, any nonzero value (including negatives) is true
&&and||short-circuit — the right operand may never be evaluatedDo not confuse
&&/||(logical) with&/|(bitwise) — they look similar but do very different things