Bitwise Operators
Bitwise operators work on the individual bits of an integer. They're how C programs pack several on/off flags into one number, talk to hardware registers, and implement fast arithmetic tricks — everyday tools in systems and embedded programming.
Binary in a nutshell
Each bit of an integer is a power of two. The 8-bit value 0b00101101 is 32 + 8 + 4 + 1 = 45. Hexadecimal is a compact way to write bits — each hex digit is exactly four bits, so 0x2D is 0010 1101.
A helper to print an 8-bit value in binary will make the examples clearer:
#include <stdio.h> #include <stdint.h> void print_bits(uint8_t value) { for (int bit = 7; bit >= 0; bit--) { putchar((value >> bit) & 1 ? '1' : '0'); } putchar('\n'); } int main(void) { print_bits(45); print_bits(0x2D); print_bits(255); return 0; }
00101101 00101101 11111111
The operators
| Operator | Name | Each result bit is 1 when… |
|---|---|---|
a & b | AND | both bits are 1 |
a | b | OR | either bit is 1 |
a ^ b | XOR | the bits differ |
~a | NOT | the bit was 0 |
a << n | left shift | bits move n places left, zeros fill in |
a >> n | right shift | bits move n places right |
#include <stdio.h> #include <stdint.h> void print_bits(uint8_t value) { for (int bit = 7; bit >= 0; bit--) putchar((value >> bit) & 1 ? '1' : '0'); putchar('\n'); } int main(void) { uint8_t a = 0xCA, b = 0x0F; // 11001010 and 00001111 print_bits(a & b); print_bits(a | b); print_bits(a ^ b); print_bits((uint8_t) ~a); print_bits((uint8_t) (a << 2)); print_bits(a >> 4); return 0; }
00001010 11001111 11000101 00110101 00101000 00001100
Don't confuse & with && or | with ||: the logical operators treat a whole value as true/false, the bitwise ones work bit by bit.
Flags in one integer
Give each option its own bit, then combine them with |. This is how many C APIs take options — open() flags in POSIX are a familiar example.
#include <stdio.h> enum { PERM_READ = 1u << 0, // 0001 PERM_WRITE = 1u << 1, // 0010 PERM_EXECUTE = 1u << 2, // 0100 PERM_ADMIN = 1u << 3 // 1000 }; int main(void) { unsigned perms = PERM_READ | PERM_WRITE; // set two flags printf("can write? %s\n", (perms & PERM_WRITE) ? "yes" : "no"); printf("can execute? %s\n", (perms & PERM_EXECUTE) ? "yes" : "no"); perms |= PERM_EXECUTE; // turn a flag on perms &= ~PERM_WRITE; // turn a flag off perms ^= PERM_ADMIN; // toggle a flag printf("perms = %u (read %d, write %d, exec %d, admin %d)\n", perms, !!(perms & PERM_READ), !!(perms & PERM_WRITE), !!(perms & PERM_EXECUTE), !!(perms & PERM_ADMIN)); return 0; }
can write? yes can execute? no perms = 13 (read 1, write 0, exec 1, admin 1)
| Task | Idiom |
|---|---|
| Set a bit | x |= FLAG; |
| Clear a bit | x &= ~FLAG; |
| Toggle a bit | x ^= FLAG; |
| Test a bit | if (x & FLAG) |
!! turns any non-zero value into exactly 1.
Masks and fields
Several small values can share one integer. An RGB colour packs red, green and blue into 24 bits; shifts and masks pull them apart:
#include <stdio.h> #include <stdint.h> int main(void) { uint32_t colour = 0x3A7BD5; unsigned red = (colour >> 16) & 0xFF; unsigned green = (colour >> 8) & 0xFF; unsigned blue = colour & 0xFF; printf("rgb(%u, %u, %u)\n", red, green, blue); uint32_t rebuilt = (red << 16) | (green << 8) | blue; printf("#%06X\n", (unsigned) rebuilt); return 0; }
rgb(58, 123, 213) #3A7BD5
Shifts as multiplication
Shifting left by n multiplies by 2n, and shifting an unsigned value right by n divides by 2n. Modern compilers already do this optimisation, so write * 8 when you mean multiplication and save shifts for bit work.
Rules to stay safe
- Use unsigned types for bit manipulation. Shifting a negative number left, or a 1 into the sign bit, is undefined behaviour; right-shifting a negative number is implementation-defined.
- Don't shift by the width or more —
x << 32on a 32-bit value is undefined. - Parenthesise.
&,^and|have lower precedence than==.
Try it yourself
Count how many bits are set in a number by repeatedly testing the lowest bit and shifting right. (A neat trick: n &= n - 1 clears the lowest set bit.)
0xF0F1 has 9 bits set