Guía completa de C++17 - std::byte de componentes

std::byte

A través de std::byte, C++17se introduce un tipo para representar la unidad de memoria más pequeña: byte. std::byteEsencialmente representa el valor de un byte , pero no puede realizar operaciones numéricas o de caracteres, ni interpreta cada bit . Esto es más seguro para los tipos en escenarios donde no se requieren cálculos numéricos ni secuencias de caracteres.
Sin embargo, tenga en cuenta que std::bytela implementación tiene el mismo tamaño que unsigned chary , lo que significa que no se garantiza que sea de 8 bits, podría ser más.

std::byte: Representa la unidad de direccionamiento , pero no tiene función como tipo entero. std::byte Puede hacer operaciones bit a bit, pero no charoperaciones algebraicas ordinarias como esa. Además de mejorar la seguridad tipográfica, también ayuda a mejorar la legibilidad del programa.

Extracto de C++17: std::byte

Quizás se pregunte cuál es la diferencia con solo usar el uint8_t existente en lugar de std::byte. Bueno, std::byte es en realidad solo un montón de bits no interpretados. Si usa uint8_t, en realidad está interpretando los bits como un Valor numérico sin signo de 8 bits, que podría transmitir una semántica
std::byteincorrecta . Además, std::byte no permitirá aritmética accidental en él, mientras que uint8_t sí uint8_t. Valor simbólico. Utilice std::byteuna semántica que evite errores y evite operaciones aritméticas accidentales.

Extracto de cppreference.com

std::byte es un tipo independiente que implementa C++el concepto de bytes especificado en la definición del lenguaje.
Al igual que char y unsigned char, se puede usar para acceder a la memoria sin procesar (representación de objetos) ocupada por otros objetos, pero a diferencia de estos tipos, no es un tipo de carácter ni un tipo aritmético. byte es solo una colección de bits, y solo los operadores bit a bit están definidos en él.

Extracto de una definición de tipo de byte

Muchos programas requieren acceso a nivel de byte a la memoria. Actualmente, estos procedimientos deben implementarse utilizando los tipos char, signed charo unsigned char. Sin embargo, estos tipos realizan una "triple función". No solo se utilizan para el direccionamiento de bytes, sino también como tipos aritméticos y tipos de caracteres. Esta variedad de roles abre la puerta a errores del programador (como realizar accidentalmente operaciones aritméticas en la memoria que deben tratarse como valores de bytes) y confusión.
byteLa introducción de tipos mejora la seguridad de tipos al distinguir entre accesos a memoria basados ​​en bytes y accesos a memoria como caracteres o valores enteros. Mejora la legibilidad y hace que la intención del código se comunique más claramente al lector (y las herramientas para comprender y transformar el programa). Aumenta la precisión de la expresión al eliminar la ambigüedad en la expresión de la intención del programador, mejorando así la seguridad de los tipos y aumentando la precisión de las herramientas de análisis.

usarstd::byte

std::bytees un tipo separado, no forma parte de los tipos de caracteres o enteros . Se utiliza para acceder a los bits que componen el almacenamiento de objetos para aumentar la seguridad del programa.
El siguiente código demuestra std::bytelas capacidades básicas:

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

using namespace std;
int main() {
    
    
    byte b1{
    
    0x3F};
    byte b2{
    
    0b1111'0000};
    cout << to_integer<int>(b1) << '\n'; // 输出: 63
    byte b3[4]{
    
    b1, b2, std::byte{
    
    1}};  // 4个字节(最后一个是0)
    if (b1 == b3[0]) {
    
    
        b1 <<= 1;
    }
    cout << to_integer<int>(b1) << '\n';  // 输出:126
    return 0;
}

El código de preprocesamiento es el siguiente:

  std::byte b1 = {
    
    63};
  std::byte b2 = {
    
    240};
  std::operator<<(std::cout.operator<<(std::to_integer<int>(b1)), '\n');
  std::byte b3[4] = {
    
    b1, b2, std::byte{
    
    1}, 0};
  if(b1 == b3[0]) {
    
    
    std::operator<<=(b1, 1);
  } 
  
  std::operator<<(std::cout.operator<<(std::to_integer<int>(b1)), '\n');

Aquí, definimos dos bytes con diferentes valores iniciales. b2La inicialización de utiliza dos C++14características introducidas:

  • El prefijo 0bpermite la definición de literales binarios
  • Un separador de números ' mejora la legibilidad de los literales numéricos (se puede colocar entre dos números cualesquiera en un literal numérico).
    Tenga en cuenta que la inicialización de la lista (inicialización con llaves) es la única std::byteforma de inicializar un objeto directamente. Todas las demás formas fallan al compilar:
std::byte b1{
    
    42};       // OK(因为自从C++17起所有枚举都有固定的底层类型)
std::byte b2(42);       // ERROR
std::byte b3 = 42;      // ERROR
std::byte b4 = {
    
    42};    // ERROR

Esta es std::byteuna consecuencia directa de haber sido implementado como un tipo enumerado . La inicialización de llaves utiliza la nueva enumeración de ámbito de inicialización con función de valor entero .
Tampoco hay conversiones de tipo implícitas, lo que significa que debe convertir explícitamente valores enteros para inicializar matrices de bytes :

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

Si no se inicializa, std::byteel valor del objeto no estará definido ya que se almacena en la pila:

std::byte b;    // 值未定义

Como de costumbre (excepto para los tipos atómicos), puede usar llaves para forzar que cada bit sea 0:

std::byte b{
    
    };  // 等价于b{0}

std::to_integer<>Le permite std::byteconvertir objetos a valores enteros (incluidos booly chartipos). Sin conversión, el operador de salida no se puede utilizar. Tenga en cuenta que debido a que esta función de conversión es una plantilla, debe usar std::el nombre completo con:

std::cout << b1;    // ERROR
std::cout << to_integer<int>(b1);       // ERROR(ADL在这里不起作用)
std::cout << std::to_integer<int>(b1);  // OK

También es posible usar usingdeclaraciones (pero solo en el ámbito local):

using std::to_integer;
...
std::cout << to_integer<int>(b1);       // OK

Esta conversión también es necesaria si se va a std::byteutilizar como valor. boolPor ejemplo:

if (b2) ...                         // ERROR
if (b2 != std::byte{
    
    0}) ...         // OK
if (to_integer<bool>(b2)) ...       // ERROR(ADL在这里不起作用)
if (std::to_integer<bool>(b2)) ...  // OK

Dado que std::byteel tipo subyacente se implementa como unsigned charun tipo de enumeración, su tamaño siempre es 1:

std::cout << sizeof(b);             // 总是1

Su número de dígitos depende del unsigned charnúmero de dígitos del tipo subyacente y puede obtener el número de dígitos con restricciones numéricas estándar:

std::cout << std::numeric_limits<unsigned char>::digits; // std::byte的位数

Esto es equivalente a:

std::cout << std::numeric_limits<std::underlying_type_t<std::byte>>::digits;

La mayoría de las veces el resultado es 8, pero en algunas plataformas puede no serlo.

std::bytetipo y funcionamiento

std::bytetipo

En el archivo de encabezado <cstddef>, C++la biblioteca estándar se define de la siguiente manera std::byte:

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

Es decir, std::bytenada más que un tipo de enumeración con ámbito con algunas operaciones de operador bit a bit :

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;
}

std::bytefuncionar

La tabla std::bytede operaciones enumera std::bytetodas las operaciones.

funcionar Efecto
Constructor Cree un objeto de bytes (el valor no está definido cuando se llama al constructor predeterminado)
incinerador de basuras destruye un objeto de bytes (no hace nada)
= asignar nuevo valor
==、!=、<、<=、>、>= comparar objetos de bytes
<<、>>、|、&、^、~ operador bit a bit binario
<<=、>>=、|=,&=、^= operador bit a bit que se modifica a sí mismo
to_integer<T>() Convierte un objeto de bytes en un tipo enteroT
sizeof() volver 1
#include <bitset>
#include <cstddef>
#include <iostream>

std::ostream& operator<<(std::ostream& os, std::byte b) {
    
    
    return os << std::bitset<8>(std::to_integer<int>(b));
}

int main() {
    
    
    std::byte b{
    
    42};
    std::cout << "1. " << b << '\n';

    // b *= 2 compilation error
    b <<= 1;
    std::cout << "2. " << b << '\n';

    b >>= 1;
    std::cout << "3. " << b << '\n';

    std::cout << "4. " << (b << 1) << '\n';
    std::cout << "5. " << (b >> 1) << '\n';

    b |= std::byte{
    
    0b11110000};
    std::cout << "6. " << b << '\n';

    b &= std::byte{
    
    0b11110000};
    std::cout << "7. " << b << '\n';

    b ^= std::byte{
    
    0b11111111};
    std::cout << "8. " << b << '\n';
}

El resultado de la operación es el siguiente:

1. 00101010
2. 01010100
3. 00101010
4. 01010100
5. 00010101
6. 11111010
7. 11110000
8. 00001111

Convertir a tipo entero

Puede convertir a cualquier tipo de entero básico ( , tipo to_integer<>()de carácter o tipo de entero). Esto también es necesario, por ejemplo, para comparar con un valor entero o usarlo como condición:std::byteboolstd::byte

if (b2) ...                         // ERROR
if (b2 != std::byte{
    
    0}) ...         // OK
if (to_integer<bool>(b2)) ...       // ERROR(ADL在这里不生效)
if (std::to_integer<bool>(b2)) ...  // OK

Otro ejemplo de su uso es std::byteI/O. to_integer<>()Úselo static_castpara unsigned charconvertir al tipo de objetivo. Por ejemplo:

std::byte ff{
    
    0xFF};
std::cout << std::to_integer<unsigned int>(ff); // 255
std::cout << std::to_integer<int>(ff);          // 也是255(没有负值)
std::cout << static_cast<int>(std::to_integer<signed char>(ff)); // -1

std::byteE/S objetivo

std::byteNo se definen operadores de entrada y salida, por lo que debe convertirse a un tipo entero para E/S:

std::byte b;
...
std::cout << std::to_integer<int>(b);   // 以十进制值打印出值
std::cout << std::hex << std::to_integer<int>(b); // 以十六进制打印出值

std::bitset<>Puede generar un valor (una secuencia de bits) en binario usando :

#include <cstddef>  // for std::byte
#include <bitset>   // for std::bitset
#include <limits>   // for std::numeric_limits

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

El ejemplo anterior usingdeclara y define una cantidad de dígitos y std::byteel mismo tipo de conjunto de bits, luego convierte el objeto de byte en un número entero para inicializar un objeto de este tipo y finalmente genera el objeto. El valor final 42 se emitiría de la siguiente manera (suponiendo que uno charsea de 8 bits):

00101010

Además, puede usar std::underlying_type_t<std::byte>en su lugar unsigned charpara que el propósito de la declaración de uso sea más obvio.

También puede usar este método para std::byteescribir la representación binaria de en una cadena:

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

byteSi ya tiene una secuencia de caracteres, también puede usar secuencias de bits como esta

#include <bitset>
#include <charconv>
#include <cstddef>
#include <iostream>

int main() {
    
    
    std::byte b1{
    
    42};
    char str[100];
    std::to_chars_result res =
        std::to_chars(str, str + 99, std::to_integer<int>(b1), 2);
    *res.ptr = '\0';  // 确保最后有一个空字符结尾

    std::cout<< std::string(str); // 101010
}

Tenga en cuenta que este formulario no escribirá ceros iniciales, lo que significa que para el valor 42, el resultado final es (suponiendo que uno chartenga 8 bits):

101010

La entrada se puede hacer de manera similar: bitsetleer como enteros, cadenas o tipos y convertir. Por ejemplo, podría implementar un operador de entrada que lea la representación binaria de un objeto de bytes como este:

std::istream& operator>> (std::istream& strm, std::byte& b)
{
    
    
    // 读入一个bitset:
    std::bitset<std::numeric_limits<unsigned char>::digits> bs;
    strm >> bs;
    // 如果没有失败就转换为std::byte:
    if (!std::cin.fail()) {
    
    
        b = static_cast<std::byte>(bs.to_ulong());  // OK
    }
    return strm;
}

Tenga en cuenta que tenemos que usar static_cast<>()para convertir bitsetel convertido unsigned longa std::byte. La inicialización de la lista no funcionará porque se produce un estrechamiento :

b = std::byte{
    
    bs.to_ulong()};   // ERROR:发生窄化

Y no tenemos otros métodos de inicialización.

Alternativamente, también puede std::from_chars()leer de una secuencia dada de caracteres con:

#include <charconv>

const char* str = "101001";
int value;
std::from_chars_result res = std::from_chars(str, str+6, // 要读取的字符范围
                                             value,      // 读取后存入的对象
                                             2);         // 2进制

Supongo que te gusta

Origin blog.csdn.net/MMTS_yang/article/details/130773279
Recomendado
Clasificación