C++17之std::byte

本文深入探讨了C++17引入的std::byte类型,解释了它与传统char和int类型的区别,展示了如何在代码中使用std::byte进行位操作,以及如何将其转换为整数类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序在内存中保存数据。在c++ 17引入了 一种std::byte类型,它确实表示内存元素的“nature”类型字节。与char或int类型的关键区别在于,它不是字符类型且非算术类型。 byte 只是位的汇集,而且只对它定义逐位运算符。即唯一支持的“计算”操作是位操作符。

1. std::byte的使用

下面的例子演示了std::byte:

#include <cstddef> // for std::byte

std::byte b1{0x3F};
std::byte b2{0b1111'0000};
std::byte b4[4] {b1, b2, std::byte{1}}; // 4 bytes (last is 0)

if (b1 == b4[0]) 
{
    b1 <<= 1;
}

std::cout << std::to_integer<int>(b1) << '\n'; // outputs: \T{126}

这里,我们用两个不同的初值定义了两个字节。b2初始化使用c++ 14以来可用的两个特性:

  • 前缀0b定义二进制文字。
  • “数字分隔符”使数字文字在源代码中更具可读性(它可以放在任何两个数字文字之间)。

注意,列表初始化(使用大括号)是直接初始化std::byte对象的单个值的唯一方法

std::byte b1{42}; // OK (as for all enums with fixed underlying type since C++17)
std::byte b2(42); // ERROR
std::byte b3 = 42; // ERROR
std::byte b4 = {42}; // ERROR

    这是将std::byte实现为枚举类型的直接结果,使用新的方法可以用整数值。由于 C++17 放松的 enum class 初始化规则,能用 std::byte{n} 转换数值 n 为 byte 值。能用 std::to_integer 转换 byte 为数值(例如生成对象的整数哈希)。

    也没有隐式转换,所以你必须用显式转换的整数文字初始化字节数组:

std::byte b5[] {1}; // ERROR
std::byte b5[] {std::byte{1}}; // OK

如果不进行任何初始化,std::byte的值将为堆栈上的对象未定义:

std::byte b; // undefined value

与往常一样(除了atomics),可以强制初始化,所有的位都设置为零,并使用列表初始化:

std::byte b{}; // same as bf0g

std::to_integer<>()提供了使字节对象转换为整数值的方法(包括bool和char)。如果没有转换,输出操作符将无法编译。注意,因为std::to_integer<>是一个模板:

std::cout << b1; // ERROR
std::cout << to_integer<int>(b1); // ERROR (ADL doesn’t work here)
std::cout << std::to_integer<int>(b1); // OK

使用std::byte作为布尔值也需要这样的转换。例如:

if (b2) ... // ERROR
if (b2 != std::byte{0}) ... // OK
if (to_integer<bool>(b2)) ... // ERROR (ADL doesn’t work here)
if (std::to_integer<bool>(b2)) ... // OK

因为std::byte被定义为枚举类型,并且unsigned char作为底层类型,所以std::byte的大小总是1:

std::cout << sizeof(b); // always 1

位的数量取决于无符号字符类型的位的数量,可以通过标准的数字限制找到:

std::cout << std::numeric_limits<unsigned char>::digits; // number of bits of a std::byte

std::byte大多数时候是8bit,但是有些平台不是这样的。

2. std::byte的类型和操作

本节详细描述std::byte的类型和操作。

2.1 std::byte的类型

在头文件<cstddef>中,c++标准库定义了std::byte类型,如下所示:

namespace std 
{
    enum class byte : unsigned char 
    {
    };
}

也就是说,std::byte只是一个作用域枚举类型,定义了一些补充的位操作符:

namespace std 
{
    ...
    template<typename IntType>
    constexpr byte operator<< (byte b, IntType shift) noexcept;

    template<typename IntType>
    constexpr byte& operator<<= (byte& b, IntType shift) noexcept;

    template<typename IntType>
    constexpr byte operator>> (byte b, IntType shift) noexcept;

    template<typename IntType>
    constexpr byte& operator>>= (byte& b, IntType shift) noexcept;

    constexpr byte& operator|= (byte& l, byte r) noexcept;

    constexpr byte operator| (byte l, byte r) noexcept;

    constexpr byte& operator&= (byte& l, byte r) noexcept;

    constexpr byte operator& (byte l, byte r) noexcept;

    constexpr byte& operator^= (byte& l, byte r) noexcept;

    constexpr byte operator^ (byte l, byte r) noexcept;

    constexpr byte operator~ (byte b) noexcept;

    template<typename IntType>
    constexpr IntType to_integer (byte b) noexcept;
}

2.2 std::byte操作

std::byte操作
操作说明
constructors创建std::byte对象(使用默认构造函数未定义值)
destructor销毁一个byte对象(不做任何操作)
=分配一个新值
==, !=, <, <=, >, >=比较byte对象
<<, >>, |, &, ^, ~二进制位的运算
<<=, >>=, |=, &=, ^=修改二进制位的运算
to_integer<T>()将byte对象转换为整数类型T
sizeof()byte的大小,一般是1

1. 转换为整数类型

通过使用to_integer<>()可以将std::byte转换为任何基本的整数类型(bool,char,int...),例如,这对于将std::byte与数值进行比较或在条件下使用它是必要的:

if (b2) ... // ERROR
if (b2 != std::byte{0}) ... // OK
if (to_integer<bool>(b2)) ... // ERROR (ADL doesn’t work here)
if (std::to_integer<bool>(b2)) ... // OK

to_integer<>()使用从无符号字符到目标类型的静态强制转换规则。例如:

std::byte ff{0xFF};
std::cout << std::to_integer<unsigned int>(ff); // 255
std::cout << std::to_integer<int>(ff); // also 255 (no negative value)
std::cout << static_cast<int>(std::to_integer<signed char>(ff)); // -1

2. I/O与std::byte

没有为std::byte定义输入和输出操作符,因此必须将它们转换为整数值:

std::byte b;
...
std::cout << std::to_integer<int>(b); // prints value as decimal value
std::cout << std::hex << std::to_integer<int>(b); // prints value as hexadecimal value

通过使用std::bitset<>,还可以输出二进制值(位序列):

#include <bitset>
#include <limits>

using ByteBitset = std::bitset<std::numeric_limits<unsigned char>::digits>;
std::cout << ByteBitset{std::to_integer<unsigned char>(b1)};

using声明定义了一个bitset类型,其位数为std::byte,然后我们创建并输出这样一个对象,该对象初始化时使用的是字节的整数类型。

也可以用它把std::byte的二进制表示写进一个字符串:

std::string s = ByteBitset{std::to_integer<unsigned char>(b1)}.to_string();

输入也可以采用类似的方法:只需将值读入整数、字符串或位集值并进行转换。

例如,可以编写一个输入操作符,从二进制表示中读取一个字节,如下所示:

std::istream& operator>> (std::istream& strm, std::byte& b)
{
// read into a bitset:
std::bitset<std::numeric_limits<unsigned char>::digits> bs;
strm >> bs;
// without failure, convert to std::byte:
if (! std::cin.fail()) {
b = static_cast<std::byte>(bs.to_ulong()); // OK
}
return strm;
}

注意,我们必须使用static_cast<>()来转换为bitset,将位bitset换为无符号long,再转换为std::byte。列表初始化无法工作,因为转换范围缩窄:

b = std::byte{bs.to_ulong()}; // ERROR: narrowing

下面举个例子:

#include <iostream>
#include <string>
#include <cstddef>
#include <bitset>
#include <limits>

int main()
{
    std::byte b1{ 0x3F };
    std::byte b2{ 0b1111'0000 };
    std::byte b4[4]{ b1, b2, std::byte{1} }; // 4 bytes (last is 0)
    std::byte b5[]{ std::byte{1} };
    std::byte b6{};

    

    if (b2 == std::byte{ 0b1111'0000 })
    {
        std::cout << std::to_integer<int>(b2) << std::endl;
    }

    using ByteBitset = std::bitset<std::numeric_limits<unsigned char>::digits>;
    std::cout << ByteBitset{ std::to_integer<unsigned char>(b1) } << std::endl;

    std::string s = ByteBitset{ std::to_integer<unsigned char>(b2) }.to_string();
    std::cout << s << std::endl;

    return 0;
}

结果如下:

 

 

 

 

 


 

 

 

 

 

 

C++中,将数据从文件读取到`std::vector<std::byte>`可以分为以下几个步骤: 1. **包含头文件**: 首先,需要包含必要的文件,如`fstream`用于文件操作和`vector`容器的定义: ```cpp #include <fstream> #include <vector> #include <array> // 如果数据是以字节序列的形式存储,如二进制数组 ``` 2. **创建并打开文件**: 定义一个`std::ifstream`流对象来打开文件,如果文件不存在则可以设置错误处理: ```cpp std::ifstream file("your_file_name", std::ios::binary); if (!file) { // 处理文件打开失败的情况 return; } ``` 3. **指定数据大小**(假设你知道数据长度): 确定数据在文件中的长度,并分配相应大小的`std::vector<std::byte>`: ```cpp size_t dataSize = ...; // 数据的实际长度 std::vector<std::byte> data(dataSize); ``` 4. **读取数据**: 使用`read`函数从文件流中读取字节到`std::vector<std::byte>`中: ```cpp file.read(reinterpret_cast<char*>(data.data()), dataSize); ``` `reinterpret_cast<char*>(data.data())`用于将`std::vector<std::byte>`的首地址转换为`char*`,以便`read`函数能正确地读取字节。 5. **检查读取是否成功**: 检查`read`操作是否完全读取了所有数据,如果没有,则可能是错误或文件不足: ```cpp if (file.gcount() != dataSize) { // 处理读取不完全的情况 } file.close(); // 关闭文件 ``` 6. **异常处理**: 还可以在适当的地方添加异常处理,比如文件关闭时可能出现异常: ```cpp try { // 执行以上操作 } catch (const std::exception& e) { // 处理异常 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值