Bit manipulation involves the use of bitwise operators to perform operations at the bit level. These operations are efficient and are commonly used in low-level programming, such as device drivers, cryptography, and graphics.
std::bitset
#include <bitset>
std::bitset<8> mybitset {}; // 8 bits in size means room for 8 flags
#include <bitset> // for std::bitset
std::bitset<8> bits{ 0b0000'0101 }; // 8 bits, initial bit pattern 0000 0101
bits.set(3); // set bit position 3 to 1 (now 0000 1101)
bits.flip(4); // flip bit 4 (now 0001 1101)
bits.reset(4); // set bit 4 back to 0 (now 0000 1101)
[[maybe_unused]] constexpr int isHungry { 0 };
size()
: Returns the number of bits in the bitset.count()
: Returns the number of bits set to true
.all()
: Returns true
if all bits are set to true
.any()
: Returns true
if any bit is set to true
.none()
: Returns true
if no bits are set to true
.Operator | Symbol | Form | Operation |
---|---|---|---|
Left shift | << | x << y |
Shifts all bits in x left by y bits |
Right shift | >> | x >> y |
Shifts all bits in x right by y bits |
Bitwise NOT | ~ | ~x |
Flips all bits in x |
Bitwise AND | & | x & y |
AND operation on each bit of x and y |
Bitwise OR | | | x | y |
OR operation on each bit of x and y |
Bitwise XOR | ^ | x ^ y |
XOR operation on each bit of x and y |
#include <bitset>
std::bitset<4> x { 0b1100 };
std::cout << (x >> 1) << '\n'; // 0110
std::cout << (x << 1) << '\n'; // 1000
std::cout << (x << 3) << '\n'; // 0000
std::cout << ~std::bitset<4>{ 0b0100 } << '\n';
std::cout << (std::bitset<4>{ 0b0101 } | std::bitset<4>{ 0b0110 } | std::bitset<4>{ 0b0001 }) << '\n'; // 0111
std::cout << (std::bitset<4>{ 0b0101 } & std::bitset<4>{ 0b0110 }) << '\n'; // 0100
std::cout << (std::bitset<4>{ 0b0001 } & std::bitset<4>{ 0b0011 } & std::bitset<4>{ 0b0111 }) << '\n'; // 0001
std::bitset<4> bits {0b0101};
bits >>= 1; // same as bits = bits >> 1
std::uint8_t cneg { ~c }; // error: narrowing conversion from unsigned int to std::uint8_t
std::uint8_t cneg { static_cast<std::uint8_t>(~c) }; // compiles
Bitwise operators promote operands with narrower integral types to int
or unsigned int
. Use static_cast
to convert the result back to the narrower integral type.
Bit masks use 0s to mask out bits and 1s to denote bits to be modified.
// Using binary literals
constexpr std::uint8_t mask0{ 0b0000'0001 }; // bit 0
constexpr std::uint8_t mask1{ 0b0000'0010 }; // bit 1
// Using hexadecimal literals
constexpr std::uint8_t mask0{ 0x01 }; // hex for 0000 0001
// Using bit shifts
constexpr std::uint8_t mask0{ 1 << 0 }; // 0000 0001
constexpr std::uint8_t mask1{ 1 << 1 }; // 0000 0010
constexpr std::uint8_t mask0{ 0b0000'0001 }; // bit 0
constexpr std::uint8_t mask1{ 0b0000'0010 }; // bit 1
std::uint8_t flags{ 0b0000'0101 }; // initial flags
std::cout << "bit 0 is " << (static_cast<bool>(flags & mask0) ? "on\n" : "off\n");
std::cout << "bit 1 is " << (static_cast<bool>(flags & mask1) ? "on\n" : "off\n");
flags |= mask1; // turn on bit 1
flags |= (mask4 | mask5); // turn on bits 4 and 5
flags &= ~mask2; // turn off bit 2
flags &= static_cast<std::uint8_t>(~mask2); // turn off bit 2
flags &= ~(mask4 | mask5); // turn off bits 4 and 5
flags ^= mask2; // flip bit 2
flags ^= (mask4 | mask5); // flip bits 4 and 5
void someFunction(std::bitset<32> options);
constexpr std::uint32_t redBits{ 0xFF000000 };
// Isolate the red component and shift into lower 8 bits
const std::uint8_t red{ static_cast<std::uint8_t>((pixel & redBits) >> 24) };