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);
}10001000In 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);
}11101110Here, 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);
}11100110In 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);
}10110011Here, 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: 51Operations 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::bytein advance. - For
operator~,operator<<,operator>>,operator<<=, andoperator>>=, the integer operand is treated as a count of bits, and thestd::byteis 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: 42std::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::byteobjects or between astd::byteand 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.