基础概念
c++17引入了std::byte来表示一个字节,相对于早期版本的char或者unsinged char来表示字节,它的好处是std::byte不是一个字符类型,而使用char或者unsigned char来表示一个字节,会解释为字符类型,它具有如下特点:
- 仅支持创建时初始化或复制初始化
- 该类型不支持算术运算,比如++、--、+、-、*、/等
- 仅支持位运算
其依赖的头文件:#include <cstddef>
std::byte的简单实现:
enum class byte : unsigned char {};
从上面可以看出std::byte本质上是强枚举类型。
使用std::byte的好处是可以明确的区分字符类型和二进制数据类型。
基本使用方法
#include <cstddef>
void example()
{
//创建
std::byte b1{42}; //正确
std::byte b2{0xff}; //正确
std::byte b3 = std::byte{0}; //正确
// 编译错误的情况
// std::byte b4 = 42; // 错误:不允许隐式转换
// std::byte b5{256}; // 错误:值超出范围
// std::byte b6 = 0xFF; // 错误:不允许隐式转换
}
位运算
void byte_operations() {
std::byte b1{0x0F}; // 0000 1111
std::byte b2{0xF0}; // 1111 0000
// 位运算
std::byte result1 = b1 | b2; // 位或:1111 1111
std::byte result2 = b1 & b2; // 位与:0000 0000
std::byte result3 = b1 ^ b2; // 位异或:1111 1111
std::byte result4 = ~b1; // 位取反:1111 0000
// 移位操作
std::byte shift1 = b1 << 2; // 左移:0011 1100
std::byte shift2 = b1 >> 1; // 右移:0000 0111
// 复合赋值
std::byte compound = b1;
compound |= b2; // 位或赋值
compound &= b2; // 位与赋值
compound ^= b2; // 位异或赋值
compound <<= 2; // 左移赋值
compound >>= 1; // 右移赋值
}
类型转换操作
void byte_conversions() {
std::byte b{0x42};
// 转换为整数类型
int i = std::to_integer<int>(b); // 66
unsigned char uc = std::to_integer<unsigned char>(b); // 0x42
// 从一个类型创建 std::byte
auto b1 = std::byte{0x42}; // 直接从字面量
auto b2 = static_cast<std::byte>(0x42); // 使用 static_cast
// 在字节数组和其他类型之间转换
int32_t value = 0x12345678;
const std::byte* byte_ptr = reinterpret_cast<const std::byte*>(&value);
// 创建字节数组
std::array<std::byte, 4> bytes;
std::memcpy(bytes.data(), &value, sizeof(value));
}
从上面的例子可以看到,std::byte类型的变量与其他类型的之间的转换方法。需要显式的进行转换。
应用场景
由于std:byte可以明确的表示数据是非字符数据,它的应用场景一般有如下场景:
- 网络数据接收:如果网络收发发送的是二进制数据,可以考虑使用std::byte进行处理
- 文件io操作:如果一个文件是二进制数据文件,应该优先考虑使用std::byte
网络协议实现的例子:
class NetworkPacket {
private:
std::vector<std::byte> packet_data;
public:
void add_header(uint8_t type) {
packet_data.push_back(std::byte{type});
}
void add_payload(const void* data, size_t size) {
const std::byte* bytes = static_cast<const std::byte*>(data);
packet_data.insert(packet_data.end(), bytes, bytes + size);
}
std::vector<std::byte> get_packet() const {
return packet_data;
}
};
文件操作的例子:
class BinaryFile {
public:
static std::vector<std::byte> read_file(const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
if (!file) {
throw std::runtime_error("Cannot open file");
}
// 获取文件大小
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
// 读取文件内容
std::vector<std::byte> buffer(size);
file.read(reinterpret_cast<char*>(buffer.data()), size);
return buffer;
}
static void write_file(const std::string& filename,
const std::vector<std::byte>& data) {
std::ofstream file(filename, std::ios::binary);
if (!file) {
throw std::runtime_error("Cannot create file");
}
file.write(reinterpret_cast<const char*>(data.data()),
data.size());
}
};