thecodex.expert · The Codex Family of Knowledge
C

Bitwise Operations

Writing & when you meant && is a real, easy-to-miss bug — both compile, and they do genuinely different things.

C17 / C23 & is not && Last verified:
Canonical Definition

Bitwise operators work on an integer's underlying binary representation, bit by bit: & sets a result bit only where both operands have a 1, | sets it where either does, ^ (XOR) sets it where exactly one does, ~ flips every bit, and <</>> shift bits left or right by a given count. These are distinct from C's logical operators (&&, ||), which treat their operands as whole true/false values — confusing & for && (or | for ||) compiles without error but produces genuinely different, usually wrong, results.

The six operators on real bit patterns

Working through actual binary makes each operator's behavior concrete rather than abstract.

Cbit_basics.c
unsigned char a = 0b1100;   // 12
unsigned char b = 0b1010;   // 10

printf("%d\n", a & b);    // 0b1000 = 8  — 1 only where BOTH have a 1
printf("%d\n", a | b);    // 0b1110 = 14 — 1 where EITHER has a 1
printf("%d\n", a ^ b);    // 0b0110 = 6  — 1 where EXACTLY ONE has a 1
printf("%d\n", a << 1);   // 0b11000 = 24 — shift left, multiplies by 2
printf("%d\n", a >> 1);   // 0b0110 = 6  — shift right, divides by 2 (for unsigned)

Flags: packing many booleans into one integer

Each bit position represents one independent on/off flag — checking, setting, and clearing a specific flag are each a single bitwise operation, far more compact than a separate bool variable per flag.

Cflags.c
#define FLAG_READ    (1 << 0)   // 0b0001
#define FLAG_WRITE   (1 << 1)   // 0b0010
#define FLAG_EXECUTE (1 << 2)   // 0b0100

unsigned int permissions = FLAG_READ | FLAG_WRITE;   // set two flags at once

if (permissions & FLAG_WRITE) {         // check: is FLAG_WRITE set?
    printf("has write permission\n");
}

permissions &= ~FLAG_WRITE;              // clear: turn FLAG_WRITE off

& vs &&: a real, easy mistake

Both compile without any error — & does a bitwise AND on the numeric values (3 & 4 is 0, since they share no set bits), while && correctly checks whether both operands are truthy. Using the wrong one is a genuinely common bug precisely because the compiler never flags it.

Cbitwise_vs_logical.c
int x = 3, y = 4;
if (x && y) { printf("both truthy\n"); }   // correct: this DOES run (3 and 4 both nonzero)
if (x & y)  { printf("shares a bit\n"); }   // this does NOT run: 3 & 4 == 0, no shared bits

Sources

1
ISO/IEC 9899 (C Standard), "Bitwise operators," cppreference.com/w/c/language/operator_arithmetic.