In C: 0 is false, anything else is true. Simple rule, lots of pitfalls. Combined with C99's bool type, this page shows you the safe way.
int done = 0; // 0 = false while (!done) { if (condition) done = 1; // 1 = true }
#include <stdbool.h> // provides bool, true, false bool done = false; while (!done) { if (condition) done = true; }
bool is a macro for _Bool, and true/false are just 1/0. _Bool is a special type that only ever stores 0 or 1 β assigning any non-zero value stores 1._Bool b = 42; // becomes 1 (not 42) printf("%d\n", b); // β 1 int i = 42; printf("%d\n", i); // β 42
if, while, for, ternary ?:):if (0) { // not taken } if (-1) { // taken (non-zero is true) } if (42) { // taken } if (0.0) { // not taken } char *p = NULL; if (p) { // not taken (NULL is 0) }
==, !=, <, >, <=, >= is always an int, either 0 or 1 β not true/false.int a = 5, b = 3; int r = (a > b); // r == 1 (int) printf("%d\n", r); // 1 // Handy trick: add comparison results int count = 0; for (int i = 0; i < n; i++) { count += (a[i] > 0); // count positive elements }
char *p = malloc(100); if (p) { // not NULL β allocation succeeded free(p); } // equivalent if (p) { /* ... */ } if (p != NULL) { /* ... */ }
if (p). Readability-first codebases prefer if (p != NULL). Mostly a team-style question.double x = 0.1 + 0.2; if (x == 0.3) { // false! // actual x β 0.30000000000000004 }
#include <math.h> double x = 0.1 + 0.2; if (fabs(x - 0.3) < 1e-9) { // equal within tolerance }
if (x == true) is dangerousint x = 2; // 2 is truthy but not 1 if (x == true) { // NG: true is 1 β 2 == 1 is false printf("not taken\n"); } if (x) { // OK: non-zero is true printf("taken\n"); }
if (x) / if (!x). Never compare to true. If you really need 0/1, use the !!x idiom below.= vs ==if (x = 5) { // "assign 5 to x, then test 5" // always true }
if (x == 5) { // test equality }
-Wall warns on if (x = 5). Some teams use "Yoda conditions" (if (5 == x)) so a typo becomes a compile error.! precedenceif (!x && y) // (!x) && y β "x is false AND y is true" if (!(x && y)) // either x or y is false // Different meaning! Use parentheses.
if (a & b) // bitwise AND: any common set bit if (a && b) // logical AND: both a and b are truthy // a = 4 (100), b = 3 (011) // a & b β 0 (no common bit) β falsy // a && b β true (both non-zero)
!!x to normalize to 0/1! twice collapses any value into exactly 0 or 1.int x = 42; int normalized = !!x; // 42 β !42=0 β !0=1 β 1 int y = 0; int n2 = !!y; // 0 β !0=1 β !1=0 β 0
bool ready = !!(flags & FLAG_READY);bool b = (x != 0); reads better. Assigning to _Bool also auto-normalizes: _Bool b = x; works the same.&& and || evaluate left-to-right and stop as soon as the result is known.if (p != NULL && p->value > 0) { // if p is NULL, p->value is not evaluated (no crash) }
if (x == 0 || y / x > 10) { // if x is 0, y/x is not evaluated (no division by zero) }
x == 0 || y / x > 10 is safe; y / x > 10 || x == 0 can still divide by zero. Always put the guard first.// Call a function only when a flag is set if (mode_debug && log_debug(msg)) { // log_debug runs only if mode_debug is truthy }
|| returns 0 or 1, not the operand value. So x = get_value() || 10; does not give you a "default value" β it gives you 0 or 1.printf("%d %d %d %d\n", !0, !1, !!5, !!-3);if (x == true) trapint x = 2;, write a program that shows if (x == true) and if (x) taking different branches.0.1 + 0.2 == 0.3 is false, then fix it with an epsilon comparison.char *s that returns 1 when s is non-NULL and its first char is 'A'. Use && in the right order to avoid NULL deref.if: add the boolean-valued comparison expression inside a loop.