Expert · Bits, undefined behaviour and safety · topic 41 of 60 · 30 min
Bitwise operators
Explanation
Binary and hexadecimal
Computers store integers in binary: 13 is 1101 (8 + 4 + 0 + 1). Hexadecimal groups 4 bits into one digit (0–9, A–F), so a byte is two hex digits: 0xFF is 11111111 (255), 0x0F is 00001111. Hex is the usual way to write bit patterns in C; C23 also allows binary literals like 0b1101 (and GCC has long supported them as an extension).
decimal binary (8 bits) hex
13 0000 1101 0x0D
200 1100 1000 0xC8
255 1111 1111 0xFFThe operators
unsigned a = 0xC8; /* 1100 1000 */
unsigned b = 0x0D; /* 0000 1101 */
a & b → 0000 1000 = 0x08 AND: 1 only where BOTH are 1
a | b → 1100 1101 = 0xCD OR: 1 where EITHER is 1
a ^ b → 1100 0101 = 0xC5 XOR: 1 where they DIFFER
~b → 1111 … 1111 0010 NOT: flips every bit (all 32 bits of an unsigned int)
b << 2 → 0011 0100 = 0x34 shift left 2: × 4
a >> 3 → 0001 1001 = 0x19 shift right 3: ÷ 8 (25)Shifts in detail
- x << n fills with zeros on the right; for unsigned x it equals x × 2^n (modulo the type size).
- x >> n for unsigned x fills with zeros on the left (a logical shift) and equals x / 2^n.
- Right-shifting a negative signed value is implementation-defined (most compilers copy the sign bit: an arithmetic shift).
- Left-shifting a negative value, or shifting a 1 into or past the sign bit of a signed int, is undefined behaviour.
- Shifting by a negative amount or by >= the width of the type (x << 32 for a 32-bit int) is undefined behaviour.
unsigned int one_mb = 1u << 20; /* 1048576: the u suffix makes it unsigned */
uint64_t big = 1ull << 40; /* a 64-bit shift: plain 1 << 40 would be undefined (int is 32 bits) */Classic bit tricks
int is_odd(unsigned x) { return x & 1u; }
int is_power_of_two(unsigned x) { return x != 0 && (x & (x - 1)) == 0; } /* 8 = 1000, 7 = 0111 → 0 */
unsigned clear_lowest(unsigned x) { return x & (x - 1); }
int popcount(unsigned x) { /* count the 1 bits */
int n = 0;
while (x) { x &= x - 1; n++; } /* each step removes the lowest set bit */
return n;
}
/* GCC/Clang also provide __builtin_popcount; C23 adds stdc_count_ones in <stdbit.h> */Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Bitwise operators · 1/6
In this lesson you will work with individual bits.
Prefer a video by a teacher? Find free videos on “c bitwise operators and or xor shift tutorial bit tricks” on YouTube ↗
In real life: Packing an RGB colour
A display driver on a smart-watch stores a colour as one 16-bit number in RGB565 format: 5 bits red, 6 bits green, 5 bits blue. Shifts and masks pack the three values into one number and unpack them again.
#include <stdint.h>
uint16_t rgb565(uint8_t r, uint8_t g, uint8_t b) {
return (uint16_t)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
}
/* rgb565(255, 255, 255) → 0xFFFF; rgb565(255, 0, 0) → 0xF800 */Practice (0/3 done)
What is 0x0F | 0xF0?
JavaScript has the same bitwise operators (& | ^ ~ << >> and the unsigned shift >>>), working on 32-bit integers, so the same algorithms run here. Write popcount(x) that counts the 1 bits of a non-negative 32-bit number using the x & (x - 1) trick, and isPowerOfTwo(x).
unsigned x = 6; What is (x & 1) == 0 ? "even" : "odd" , and what would x & 1 == 0 (no brackets) compute?
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Masks and flagsBits, undefined behaviour and safety · same module
- Undefined behaviourBits, undefined behaviour and safety · same module
- Secure and defensive CBits, undefined behaviour and safety · same module
- Bits: AND, OR, XOR and shiftsData Structures and Algorithms (DSA) for interviews · Tries, union-find and bit manipulation
- Subnet masks, prefix length and wildcard masksComputer Networking (CCNA level) · IPv4 addressing
- Bit tricks in interviewsData Structures and Algorithms (DSA) for interviews · Tries, union-find and bit manipulation
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is 5 ^ 3?
Answer: 6
101 ^ 011 = 110 = 6.
What is 1u << 10?
Answer: 1024
2^10.
Why use unsigned types for bit manipulation?
Answer: Shifts and overflow are well defined for unsigned types
Signed shifts have implementation-defined or undefined cases.
What does x & (x - 1) do?
Answer: Clears the lowest set bit of x
Used in popcount and power-of-two tests.
Which expression clears bit 5 of x?Related
Items are [a, b, c] and bit i stands for item i. Which subset does mask 5 (binary 101) mean?Related
How many bits are in one octet?Related
Answer: 8
An octet is 8 bits. An IPv4 address has 4 octets, so 32 bits.
What type is the result of 3 + 2.0?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “Bits, undefined behaviour and safety” before its exam: Masks and flags, Undefined behaviour, Secure and defensive C, Function pointers and callbacks.
- Module 9 exam: Bits, undefined behaviour and safety · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Data structures in C. 60 topics left in the course before the final exam.