Skip to main content

Updated May 4, 2026

Bitwise Operators

Bitwise operators manipulate the individual bits of integer values. They are the building blocks of flag sets, masks, packed data, and low-level protocol code.

Where to go deeper

This page is the C++ operator reference. For the algorithmic side — counting bits, isolating the lowest set bit, parity tricks — see Bit Manipulation Techniques.

The operators​

OperatorNameEffect
&ANDbit set in result iff set in both operands
|ORbit set iff set in either operand
^XORbit set iff set in exactly one operand
~NOTflips every bit (unary)
<<left shiftmultiply by 2ⁿ (bits shifted in are zero)
>>right shiftdivide by 2ⁿ (sign-dependent — see below)
unsigned a = 0b1100;
unsigned b = 0b1010;
a & b; // 0b1000 (8)
a | b; // 0b1110 (14)
a ^ b; // 0b0110 (6)
~a; // all bits flipped — depends on width of the type
a << 1; // 0b11000 (24)
a >> 1; // 0b0110 (6)

Flag sets — the canonical use​

enum Perm : unsigned { Read = 1u << 0, Write = 1u << 1, Exec = 1u << 2 };

unsigned p = Read | Write; // set bits -> 0b011
p |= Exec; // add a flag -> 0b111
p &= ~Write; // clear a flag -> 0b101
bool can_read = p & Read; // test a flag (non-zero == set)
p ^= Exec; // toggle a flag

Shifts: the sharp edges​

Two real traps
  • Shift by ≥ the type width is undefined behaviour. x << 32 on a 32-bit int is UB, not 0.
  • Right-shifting a negative signed value is implementation-defined (arithmetic on every mainstream compiler, but not guaranteed by the standard pre-C++20).

Do bit work on unsigned types. uint32_t/uint64_t make width explicit and shifts well-defined.

uint32_t mask = 1u << 31; // OK: uint32_t literal, bit 31 set
// int bad = 1 << 31; // UB on most platforms: overflows signed int

Bitwise vs logical​

A recurring beginner bug is writing &/| where &&/|| was meant. Bitwise operators do not short-circuit and compare bit patterns, not truth values:

if (a & b) { ... } // true when a and b share any set bit
if (a && b) { ... } // true when both a and b are non-zero

See Logical Operators for the short-circuiting pair.

std::bitset and <bit>​

For readable flag handling and portable bit utilities, prefer the library over hand-rolled tricks:

#include <bitset>
#include <bit> // C++20
std::bitset<8> bs{0b1010};
bs.set(0); bs.flip(); bs.count(); // legible bit ops
int n = std::popcount(0b1011u); // 3 — set-bit count
bool p = std::has_single_bit(16u); // is power of two?

Summary​

  • & | ^ ~ work per bit; <</>> scale by powers of two.
  • Use unsigned, fixed-width types — signed shifts and overflow invite UB.
  • Shifting by ≥ the bit width is undefined behaviour.
  • &/| are not &&/||: no short-circuit, different meaning.
  • Reach for std::bitset and <bit> (popcount, has_single_bit, rotl) before clever tricks.