Bitwise Operations Explained
A practical guide to AND, OR, XOR, NOT, and bit shifts: how they work, why they matter, and where you'll use them.
What Are Bitwise Operations?
Bitwise operations manipulate data at the level of individual bits. Unlike arithmetic operations that treat numbers as abstract quantities, bitwise operators work on the binary representation directly, processing each bit position independently. They are fundamental to systems programming, embedded development, cryptography, graphics, networking protocols, and performance-critical code.
If you have ever set a flag, masked an IP address, computed a hash, toggled a GPIO pin, or wondered how x & (x - 1) clears the lowest set bit, you have used bitwise operations. This guide covers each operator with visual breakdowns and practical examples you can try in our Bitwise Playground.
AND (&)
The AND operator compares two values bit by bit. The result bit is 1 only when both corresponding input bits are 1. In all other cases, the result is 0.
AND Truth Table
Example: 0b11001010 & 0b10101010
1 1 0 0 1 0 1 0 (0xCA = 202)
& 1 0 1 0 1 0 1 0 (0xAA = 170)
─────────────────
1 0 0 0 1 0 1 0 (0x8A = 138)Practical Uses of AND
- Masking (extracting bits): AND with a mask of 1s in the positions you want to keep. To extract the lower nibble:
value & 0x0F. To extract a specific bit:value & (1 << n). - Testing flags: Check if a specific flag is set:
if (flags & FLAG_READ) {...}. The result is non-zero only if the flag bit is 1. - Clearing bits: AND with a mask where the bits to clear are 0:
value & ~(1 << n)clears bit n. - Alignment checks:
address & 0x3returns 0 if the address is 4-byte aligned, because aligned addresses have their two lowest bits as 00. - Network subnet masking:
ip & netmaskextracts the network portion of an IP address. See our Subnet Calculator.
OR (|)
The OR operator sets the result bit to 1 when either or both input bits are 1. The result is 0 only when both inputs are 0.
1 1 0 0 1 0 1 0 (0xCA = 202)
| 0 0 1 1 0 0 1 1 (0x33 = 51)
─────────────────
1 1 1 1 1 0 1 1 (0xFB = 251)Practical Uses of OR
- Setting flags:
flags | FLAG_WRITEturns on the write flag without affecting other flags. - Combining permissions: Unix file permissions combine read, write, and execute:
S_IRUSR | S_IWUSR | S_IXUSR= 0700. - Constructing values from fields: Assemble a 32-bit color from components:
(r << 16) | (g << 8) | b.
XOR (^)
The XOR (exclusive OR) operator sets the result bit to 1 when the input bits are different. When both are the same (both 0 or both 1), the result is 0. XOR is the most mathematically interesting bitwise operator; it is its own inverse, associative, and commutative.
1 1 0 0 1 0 1 0 (0xCA = 202)
^ 1 0 1 0 1 0 1 0 (0xAA = 170)
─────────────────
0 1 1 0 0 0 0 0 (0x60 = 96)Key Properties of XOR
- Self-inverse:
a ^ b ^ b = a. XORing with the same value twice returns the original. This is the basis of XOR encryption and the classic swap trick. - Identity element:
a ^ 0 = a. XOR with zero is a no-op. - Self-cancellation:
a ^ a = 0. XOR of a value with itself is always zero.
Practical Uses of XOR
- Toggling bits:
flags ^ FLAG_MUTEflips the mute flag on or off. - Finding the odd one out: XOR all elements of an array where every element appears twice except one. The result is the unique element. This is a classic interview problem with O(n) time and O(1) space.
- Simple checksums: XOR all bytes together for a quick parity check. Many serial protocols use XOR checksums.
- RAID parity: RAID-5 uses XOR to compute parity stripes, enabling data recovery from a single disk failure.
- Cryptography: Stream ciphers XOR plaintext with a keystream. The one-time pad, the only theoretically unbreakable cipher, is simply XOR with a truly random key.
NOT (~)
The NOT operator (bitwise complement) is a unary operator that flips every bit: 0 becomes 1 and 1 becomes 0.
~ 1 1 0 0 1 0 1 0 (0xCA = 202)
─────────────────
0 0 1 1 0 1 0 1 (0x35 = 53, as unsigned 8-bit)In a language with fixed-width integers, NOT is equivalent to subtracting from the maximum value: for an unsigned 8-bit integer, ~x = 255 - x. For signed integers in two's complement, ~x = -(x + 1).
Practical Uses of NOT
- Creating clearing masks:
value & ~maskclears the bits specified by the mask. For example,flags & ~FLAG_READclears the read flag. - Two's complement negation:
-x = ~x + 1. This is how hardware computes negation.
Left Shift (<<)
Left shift moves all bits toward the most significant position by a specified number of places. Vacated positions on the right are filled with zeros. Each left shift by 1 is equivalent to multiplying by 2.
0 0 0 0 1 0 1 0 (10)
<< 3
─────────────────
0 1 0 1 0 0 0 0 (80 = 10 * 2^3)Practical Uses of Left Shift
- Fast multiplication by powers of 2:
x << 3computes x × 8. Modern compilers optimize multiplication by constants into shifts automatically, but the pattern appears frequently in manual bit manipulation. - Creating bit masks:
1 << ncreates a mask with only bit n set. This is the standard way to define flag constants. - Packing data:
(day << 5) | monthpacks a day and month into a single byte.
Right Shift (>>)
Right shift moves all bits toward the least significant position. Vacated positions on the left are filled with either zeros (logical shift) or copies of the sign bit (arithmetic shift), depending on the language and the signedness of the type. Each right shift by 1 is equivalent to integer division by 2.
0 1 0 1 0 0 0 0 (80)
>> 3
─────────────────
0 0 0 0 1 0 1 0 (10 = 80 / 2^3)Practical Uses of Right Shift
- Fast division by powers of 2:
x >> 4computes x ÷ 16 (integer division, rounding toward zero for unsigned values). - Extracting bit fields:
(value >> 4) & 0x0Fextracts the upper nibble of a byte. - Sign extension: Arithmetic right shift preserves the sign of negative numbers in two's complement, filling with 1s.
Common Bit Manipulation Patterns
The following idioms appear repeatedly in systems code, algorithms, and interview problems. Each combines the basic operators into a useful higher-level operation:
// Set bit n
x | (1 << n)
// Clear bit n
x & ~(1 << n)
// Toggle bit n
x ^ (1 << n)
// Check if bit n is set
(x >> n) & 1 // returns 0 or 1
// Clear the lowest set bit
x & (x - 1) // classic: used in popcount
// Isolate the lowest set bit
x & (-x) // returns power-of-2 value
// Check if x is a power of 2
x != 0 && (x & (x - 1)) == 0
// Round up to next power of 2 (32-bit)
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
// Swap without temporary variable
a ^= b; b ^= a; a ^= b;The trick x & (x - 1) deserves special attention. Subtracting 1 from a binary number flips the lowest set bit and all bits below it. ANDing with the original clears exactly that lowest set bit. This operation is used in Kernighan's bit-counting algorithm to count set bits in O(k) time where k is the number of set bits, rather than O(n) where n is the bit width.
Bitwise Operations Across Languages
// JavaScript (all numbers are 64-bit float, bitwise ops use 32-bit int)
0xFF & 0x0F // 15
~0xFF // -256 (sign-extended 32-bit)
0xFF >>> 4 // 15 (unsigned right shift, JS-specific)
# Python (arbitrary-precision integers)
0xFF & 0x0F # 15
~0xFF # -256
0xFF >> 4 # 15
bin(0xCA & 0xAA) # '0b10001010'
// C / C++ (width depends on type)
uint8_t x = 0xFF;
~x // 0x00 (8-bit context)
// Go (width matches type)
var x uint8 = 0xFF
^x // 0x00 (Go uses ^ for bitwise NOT)
// Rust (width matches type, prevents UB)
let x: u8 = 0xFF;
!x // 0x00 (Rust uses ! for bitwise NOT)Note the important language differences: JavaScript performs bitwise operations on 32-bit signed integers and has a special >>> operator for unsigned right shift. Python integers have unlimited precision, so NOT on a positive number always produces a negative result. Go uses ^ for both XOR (binary) and NOT (unary). These distinctions matter when porting bit manipulation code between languages.
Try It Yourself
Our Bitwise Playground lets you enter two values in any base, select an operation, and see the bit-by-bit breakdown with color-coded results. Try the common patterns above and watch how each bit position is affected. Combine this with the Bit Layout tab to click individual bits and build an intuitive feel for bit manipulation.
Further Reading
- Bit Manipulation — Wikipedia
Overview of bit manipulation techniques and their applications in computing.
- Bit Twiddling Hacks
Stanford's legendary collection of clever bit manipulation tricks and algorithms.
- MDN Bitwise Operators
JavaScript-specific bitwise operator documentation with examples.
- Linux Kernel Bitmask Operations
How the Linux kernel uses bitmasks for flags, permissions, and hardware register manipulation.
- Mask (computing) — Wikipedia
Comprehensive guide to bitmasks in computing: extraction, setting, clearing, and toggling bits.