Bitwise Operations
How can I perform bitwise operations like AND or OR on variables storing binary data?
To perform bitwise operations on binary data, you'll typically use unsigned integer types like uint8_t
, uint16_t
, or uint32_t
. These types allow you to directly manipulate individual bits using operators like &
(AND), |
(OR), ^
(XOR), and ~
(NOT).
Let's say you have two bytes of data represented as uint8_t
variables, and you want to perform a bitwise AND operation:
#include <cstdint>
#include <iostream>
#include <format>
int main() {
uint8_t Byte1{0b11001100};
uint8_t Byte2{0b10101010};
// Bitwise AND
uint8_t Result = Byte1 & Byte2;
std::cout << std::format("{:b}", Result);
}
10001000
In this example, Result will hold the value 0b10001000
. Each bit in Result
is set to 1 only if the corresponding bits in both Byte1
and Byte2
are 1
.
Bitwise OR
Similarly, for a bitwise OR, you can use the |
operator:
#include <cstdint>
#include <iostream>
#include <format>
int main() {
uint8_t Byte1{0b11001100};
uint8_t Byte2{0b10101010};
uint8_t Result = Byte1 | Byte2; // Bitwise OR
std::cout << std::format("{:b}", Result);
}
11101110
Here, Result
will be 0b11101110
. A bit in Result
is set to 1 if either of the corresponding bits in Byte1
or Byte2
is 1.
Bitwise XOR
For a bitwise XOR (exclusive OR), use the ^
operator:
#include <cstdint>
#include <iostream>
#include <format>
int main() {
uint8_t Byte1{0b11001100};
uint8_t Byte2{0b00101010};
// Bitwise XOR
uint8_t Result = Byte1 ^ Byte2;
std::cout << std::format("{:b}", Result);
}
11100110
In this case, Result
will be 0b11100110
. A bit in Result
is set to 1 if the corresponding bits in Byte1
and Byte2
are different.
Bitwise NOT
Finally, the bitwise NOT operator ~
inverts the bits of a single operand:
#include <cstdint>
#include <iostream>
#include <format>
int main() {
uint8_t Byte1{0b01001100};
uint8_t Result = ~Byte1; // Bitwise NOT
std::cout << std::format("{:b}", Result);
}
10110011
Here, Result
will be 0b00110011
. Each bit in Byte1
is flipped (0 becomes 1, and 1 becomes 0).
Working With std::byte
std::byte
is designed to represent a raw byte of data, and it does support bitwise operations. However, there are some nuances to be aware of:
Operations Between Two std::byte
Objects
Bitwise operations are directly supported between two std::byte
objects. The result of such operations is another std::byte
.
#include <cstddef>
#include <iostream>
int main() {
std::byte Byte1{0b11001100};
std::byte Byte2{0b10101010};
std::byte ResultAnd{Byte1 & Byte2}; // Bitwise AND
std::byte ResultOr{Byte1 | Byte2}; // Bitwise OR
std::byte ResultXor{Byte1 ^ Byte2}; // Bitwise XOR
std::byte ResultNot{~Byte1}; // Bitwise NOT
std::cout << "Result AND: "
<< std::to_integer<int>(ResultAnd) << "\n";
std::cout << "Result OR: "
<< std::to_integer<int>(ResultOr) << "\n";
std::cout << "Result XOR: "
<< std::to_integer<int>(ResultXor) << "\n";
std::cout << "Result NOT: "
<< std::to_integer<int>(ResultNot) << "\n";
}
Result AND: 136
Result OR: 238
Result XOR: 102
Result NOT: 51
Operations Between std::byte
and Integer Types
When you perform bitwise operations between a std::byte
and an integer type (like int
or uint8_t
), the result is always a std::byte
. The result of these operations is as follows:
- For
operator&
,operator|
,operator^
,operator&=
,operator|=
, andoperator^=
, an integral type is not supported as the right operand, but we can convert it to astd::byte
in advance. - For
operator~
,operator<<
,operator>>
,operator<<=
, andoperator>>=
, the integer operand is treated as a count of bits, and thestd::byte
is shifted accordingly.
#include <cstddef>
int main() {
std::byte MyByte{0b00001111};
// Bit shifting a byte uses an integer
MyByte <<= 2;
// This won't work
MyByte &= 0b11110000;
// But we can do this
MyByte &= std::byte{0b11110000};
}
Casting with std::byte
The main purpose of std::byte
is to indicate that you're working with raw data rather than arithmetic values.
However, if you need to perform arithmetic operations or use std::byte
in contexts where an integer is expected, you can use std::to_integer
:
#include <cstddef>
#include <iostream>
int main() {
std::byte MyByte{42};
// Convert std::byte to an integer
int MyInt{std::to_integer<int>(MyByte)};
std::cout << "MyInt: " << MyInt << "\n";
}
MyInt: 42
std::byte
vs Unsigned Integers
While both std::byte
and unsigned integers can represent raw bytes of data, their intended use cases are different:
std::byte
: Primarily for representing raw data where arithmetic operations are not meaningful. Bitwise operations are supported between twostd::byte
objects or between astd::byte
and an integer.- Unsigned Integers (e.g.,
uint8_t
): Suitable for both raw data representation and numerical calculations. They support a wider range of operations, including arithmetic.
In summary, std::byte
does support bitwise operations directly, and you don't need to cast to unsigned integers when working with two std::byte
objects.
However, when mixing with integers or performing arithmetic, understanding the implicit conversions and using std::to_integer
when needed is important.
The choice between std::byte
and unsigned integers depends on whether you want to emphasize the raw data aspect or need numerical operations.
Numeric and Binary Data
Learn how C++ represents numbers and data in memory using binary, decimal, and hexadecimal systems.