std::byte
A través de std::byte
, C++17
se introduce un tipo para representar la unidad de memoria más pequeña: byte. std::byte
Esencialmente 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::byte
la implementación tiene el mismo tamaño que unsigned char
y , 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 nochar
operaciones algebraicas ordinarias como esa. Además de mejorar la seguridad tipográfica, también ayuda a mejorar la legibilidad del programa.
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::byte
incorrecta . Además, std::byte no permitirá aritmética accidental en él, mientras que uint8_t síuint8_t
. Valor simbólico. Utilicestd::byte
una semántica que evite errores y evite operaciones aritméticas accidentales.
std::byte
es un tipo independiente que implementaC++
el concepto de bytes especificado en la definición del lenguaje.
Al igual quechar
yunsigned 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 char
ounsigned 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.
byte
La 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::byte
es 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::byte
las 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. b2
La inicialización de utiliza dos C++14
características introducidas:
- El prefijo
0b
permite 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 únicastd::byte
forma 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::byte
una 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::byte
el 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::byte
convertir objetos a valores enteros (incluidos bool
y char
tipos). 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 using
declaraciones (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::byte
utilizar como valor. bool
Por 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::byte
el tipo subyacente se implementa como unsigned char
un tipo de enumeración, su tamaño siempre es 1:
std::cout << sizeof(b); // 总是1
Su número de dígitos depende del unsigned char
nú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::byte
tipo y funcionamiento
std::byte
tipo
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::byte
nada 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::byte
funcionar
La tabla std::byte
de operaciones enumera std::byte
todas 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::byte
bool
std::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::byte
I/O. to_integer<>()
Úselo static_cast
para unsigned char
convertir 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::byte
E/S objetivo
std::byte
No 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 using
declara y define una cantidad de dígitos y std::byte
el 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 char
sea de 8 bits):
00101010
Además, puede usar std::underlying_type_t<std::byte>
en su lugar unsigned char
para que el propósito de la declaración de uso sea más obvio.
También puede usar este método para std::byte
escribir la representación binaria de en una cadena:
std::string s = ByteBitset{
std::to_integer<unsigned>(b1)}.to_string();
byte
Si 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 char
tenga 8 bits):
101010
La entrada se puede hacer de manera similar: bitset
leer 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 bitset
el convertido unsigned long
a 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进制