C Bitwise Operations Cheat Sheet
Summarizes C's bitwise operators, bitmask flag patterns, and common bit manipulation tricks like counting set bits and power-of-two checks.
Bitwise Operators
The core AND, OR, XOR, NOT, and shift operators.
unsigned int a = 0xA; // 1010 in binary (10)unsigned int b = 0x6; // 0110 in binary (6)unsigned int and_result = a & b; // 0010 = 2 (AND)unsigned int or_result = a | b; // 1110 = 14 (OR)unsigned int xor_result = a ^ b; // 1100 = 12 (XOR)unsigned int not_result = ~a; // Flips all bits (bitwise NOT)unsigned int left_shift = a << 2; // 101000 = 40 (multiply by 4)unsigned int right_shift = a >> 1; // 0101 = 5 (divide by 2)
Flags with Bitmasks
Packing multiple boolean flags into one integer.
#define FLAG_READ (1 << 0) // 0001#define FLAG_WRITE (1 << 1) // 0010#define FLAG_EXECUTE (1 << 2) // 0100unsigned int perms = FLAG_READ | FLAG_WRITE; // Set multiple flags: 0011perms |= FLAG_EXECUTE; // Set a flagperms &= ~FLAG_WRITE; // Clear a flagint has_read = (perms & FLAG_READ) != 0; // Test a flagperms ^= FLAG_READ; // Toggle a flag
Common Bit Tricks
Idioms for fast, allocation-free integer operations.
int is_even = (n & 1) == 0; // Check even/odd without %int is_power_of_two = n > 0 && (n & (n - 1)) == 0; // Power-of-two checkint x = 3, y = 5;x ^= y; y ^= x; x ^= y; // Swap without a temp variable (XOR swap)unsigned int count_set_bits(unsigned int v) { int count = 0; while (v) { v &= (v - 1); // Clears the lowest set bit each iteration count++; } return count; // Brian Kernighan's algorithm}
Operators & Rules
What each operator does and where the sharp edges are.
- & (AND)- Result bit is 1 only if both operand bits are 1; used for masking/testing bits
- | (OR)- Result bit is 1 if either operand bit is 1; used for setting bits
- ^ (XOR)- Result bit is 1 if the operand bits differ; used for toggling bits
- ~ (NOT)- Unary operator that inverts every bit; result depends on the operand's bit width
- << / >>- Shift bits left/right; left-shifting into or past the sign bit of a signed int is undefined behavior
- Signed right shift- Implementation-defined for negative numbers (may be arithmetic or logical)
- Unsigned types- Prefer unsigned int for bitmask work to avoid sign-related undefined behavior
Bit-Fields in Structs
Packing sub-byte values into a struct using bit-field width specifiers.
struct PixelFlags { unsigned int alpha_enabled : 1; unsigned int color_mode : 3; // 0-7 unsigned int layer : 4; // 0-15 unsigned int reserved : 24; // pad to 32 bits total};struct PixelFlags px = {0};px.alpha_enabled = 1;px.color_mode = 5;// Layout, padding, and bit order are implementation-defined;// never rely on bit-field layout for on-wire/binary-file formats.
Two's Complement & Sign Tricks
Branchless idioms that exploit two's complement representation.
int abs_branchless(int n) { int mask = n >> (sizeof(int) * 8 - 1); // all 1s if negative, else all 0s return (n + mask) ^ mask; // negate n if mask is all 1s}int sign(int n) { return (n > 0) - (n < 0); // -1, 0, or 1 with no branches}unsigned int neg_as_unsigned = (unsigned int)(-1); // UINT_MAX, guaranteed by // two's complement wraparound
Advanced Bit Manipulation
Isolating, clearing, and rounding using classic single-line bit hacks.
unsigned int lowest_set_bit = n & (-n); // isolates the lowest 1-bitunsigned int clear_lowest = n & (n - 1); // clears the lowest 1-bitunsigned int next_pow2(unsigned int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; return v + 1; // rounds up to next power of two}unsigned int reverse_bits(unsigned int v) { unsigned int r = 0; for (int i = 0; i < 32; i++) { r = (r << 1) | (v & 1); v >>= 1; } return r;}
GCC/Clang Bit-Counting Builtins
Compiler intrinsics that compile to a single hardware instruction where available.
#include <stdio.h>unsigned int v = 0b0110'1100;int popcount = __builtin_popcount(v); // count of set bits (POPCNT)int leading_z = __builtin_clz(v); // count leading zeros (LZCNT)int trailing_z = __builtin_ctz(v); // count trailing zeros (TZCNT)int parity = __builtin_parity(v); // 1 if odd number of set bits// C23 / <stdbit.h> portable equivalents also exist: stdc_count_ones,// stdc_leading_zeros, stdc_trailing_zeros
Undefined & Implementation-Defined Behavior
Edge cases in the C standard that silently produce wrong or non-portable results.
- Shift by >= width- Shifting by a count >= the operand's bit width (e.g. `x << 32` on a 32-bit int) is undefined behavior
- Shifting negative left operand- Left-shifting a negative signed integer is undefined behavior in C
- Signed overflow- Bitwise ops on signed types that overflow the representable range are undefined; prefer unsigned types for bit manipulation
- Integer promotion- Operands smaller than int (char, short) are promoted to int before bitwise ops, which can change sign-extension results
- ~ on unsigned narrow types- ~(unsigned char)x promotes to int first, so the result has extra set high bits unless masked back down
- Endianness- Bitwise operator results are endianness-independent, but reinterpreting the same bits as bytes (via a union or cast) is not
- Bit-field portability- Bit-field member order and storage-unit boundaries are implementation-defined; unsafe for binary interchange formats
Left-shifting a signed int far enough to set or overflow the sign bit is undefined behavior in C — use unsigned types for bit manipulation and masks.