Bit Manipulation Techniques
Working directly with the individual bits of an integer, using C's bitwise operators (&, |, ^, ~, <<, >>), is a core low-level skill. It shows up constantly in embedded programming, device drivers, networking code, and any performance-critical code that needs to pack information as tightly as possible or manipulate hardware registers directly.
The recipes at a glance
Operation | Expression (bit n, 0-indexed) |
|---|---|
Check if bit n is set |
|
Set bit n |
|
Clear bit n |
|
Toggle bit n |
|
Check if x is a power of two |
|
Count set bits | loop shifting and checking the low bit (or |
Checking, setting, clearing, toggling a bit
#include <stdio.h>
int main(void) {
unsigned int x = 0b00001010; // 10 in binary
// Check if bit 1 is set: shift it to the lowest position, mask with 1.
int bit1 = (x >> 1) & 1;
printf("bit 1 is %d\n", bit1);
// Set bit 0: OR with a mask that has only bit 0 set.
x |= (1 << 0);
printf("after setting bit 0: %#x\n", x);
// Clear bit 3: AND with the complement of a mask that has only bit 3 set.
x &= ~(1 << 3);
printf("after clearing bit 3: %#x\n", x);
// Toggle bit 2: XOR with a mask that has only bit 2 set.
x ^= (1 << 2);
printf("after toggling bit 2: %#x\n", x);
return 0;
}bit 1 is 1 after setting bit 0: 0xb after clearing bit 3: 0x3 after toggling bit 2: 0x7
Checking for a power of two
A power of two has exactly one bit set (1, 10, 100, 1000, ...). Subtracting 1 from it flips that single set bit to 0 and every bit below it to 1 (e.g. 1000 - 1 = 0111), so a power of two ANDed with itself minus one is always zero — and this is not true for any number that is not a power of two.
#include <stdio.h>
#include <stdbool.h>
bool is_power_of_two(unsigned int x) {
return x > 0 && (x & (x - 1)) == 0;
}
int main(void) {
unsigned int values[] = {1, 2, 3, 4, 15, 16, 1024};
for (int i = 0; i < 7; i++) {
printf("%u: %s\n", values[i], is_power_of_two(values[i]) ? "yes" : "no");
}
return 0;
}1: yes 2: yes 3: no 4: yes 15: no 16: yes 1024: yes
Counting set bits
#include <stdio.h>
int count_set_bits(unsigned int x) {
int count = 0;
while (x != 0) {
count += x & 1; // add 1 if the lowest bit is set
x >>= 1; // shift right to examine the next bit
}
return count;
}
int main(void) {
printf("%d\n", count_set_bits(0b10110101)); // 5 bits set
return 0;
}5
These techniques matter because bitwise operators map almost directly onto what the CPU does in hardware — a handful of instructions with no branching, no memory allocation, and no loops for the single-bit operations. In embedded systems, that efficiency and predictability is often not just nice to have but required, since hardware registers are frequently manipulated one or a few bits at a time.
(x >> n) & 1checks bit n;x |= (1 << n)sets it;x &= ~(1 << n)clears it;x ^= (1 << n)toggles it.x & (x - 1)clears the lowest set bit, which is the trick behind the power-of-two check.Counting set bits by shifting and checking is O(number of bits); compiler builtins like
__builtin_popcountare often faster.These operators map closely to real CPU instructions, which is why they are favored in embedded and performance-critical code.