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.
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.
#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.
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