tutorial tipos tamaño rangos rango español ejemplos definicion datos c++ vector c++17

rangos - tipos de datos en c++ tamaño y rango



¿Cómo usar el nuevo tipo std:: byte en los lugares donde se necesita el carácter sin signo de estilo antiguo? (2)

Si desea algo que se comporte como un byte de la manera que probablemente lo esperaría, pero tiene un nombre claramente diferente al uso sin signo uint8_t de stdint.h. Para casi todas las implementaciones, esto probablemente será un

typedef unsigned char uint8_t;

y otra vez un personaje sin firma debajo del capó, pero ¿a quién le importa? Solo quieres enfatizar "Este no es un tipo de carácter". No tiene que esperar tener dos sobrecargas de algunas funciones, una para caracteres sin firmar y otra para uint8_t. Pero si lo haces, el compilador empujará tu nariz de todos modos ...

std::byte es un tipo nuevo en C ++ 17 que se realiza como enum class byte : unsigned char . Esto hace que sea imposible utilizarlo sin la conversión adecuada. Por lo tanto, he creado un alias para el vector de tal tipo para representar una matriz de bytes:

using Bytes = std::vector<std::byte>;

Sin embargo, es imposible usarlo en el estilo antiguo: las funciones que lo aceptan como parámetro fallan porque este tipo no se puede convertir fácilmente al tipo antiguo std::vector<unsigned char> , por ejemplo, un uso de la biblioteca zipper :

/resourcecache/pakfile.cpp: In member function ''utils::Bytes resourcecache::PakFile::readFile(const string&)'': /resourcecache/pakfile.cpp:48:52: error: no matching function for call to ''zipper::Unzipper::extractEntryToMemory(const string&, utils::Bytes&)'' unzipper_->extractEntryToMemory(fileName, bytes); ^ In file included from /resourcecache/pakfile.hpp:13:0, from /resourcecache/pakfile.cpp:1: /projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note: candidate: bool zipper::Unzipper::extractEntryToMemory(const string&, std::vector<unsigned char>&) bool extractEntryToMemory(const std::string& name, std::vector<unsigned char>& vec); ^~~~~~~~~~~~~~~~~~~~ /projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note: no known conversion for argument 2 from ''utils::Bytes {aka std::vector<std::byte>}'' to ''std::vector<unsigned char>&''

He intentado realizar lanzamientos ingenuos, pero esto tampoco ayuda. Entonces, si está diseñado para ser útil, ¿será realmente útil en contextos antiguos? El único método que veo es usar std::transform para usar un nuevo vector de bytes en estos lugares:

utils::Bytes bytes; std::vector<unsigned char> rawBytes; unzipper_->extractEntryToMemory(fileName, rawBytes); std::transform(rawBytes.cbegin(), rawBytes.cend(), std::back_inserter(bytes), [](const unsigned char c) { return static_cast<std::byte>(c); }); return bytes;

Cual es:

  1. Feo.
  2. Toma muchas líneas inútiles (puede ser reescrita pero aún debe escribirse antes :)).
  3. Copia la memoria en lugar de utilizar solo el fragmento de rawBytes ya creado.

Entonces, ¿cómo usarlo en lugares antiguos?


Te estás perdiendo el punto por el cual std::byte fue inventado en primer lugar. La razón por la que se inventó es para mantener un byte sin procesar en la memoria sin el supuesto de que es un carácter . Puedes ver eso en cppreference .

Al igual que char y unsigned char, se puede usar para acceder a la memoria en bruto ocupada por otros objetos (representación de objeto), pero a diferencia de esos tipos, no es un tipo de carácter y no es un tipo aritmético.

Recuerde que C ++ es un lenguaje fuertemente tipado en interés de la seguridad (por lo que las conversiones implícitas están restringidas en muchos casos). Significado: Si una conversión implícita de byte a char fuera posible, anularía el propósito.

Entonces, para responder a tu pregunta: para usarla, debes lanzarla cuando quieras asignarle una tarea:

std::byte x = (std::byte)10; std::byte y = (std::byte)''a''; std::cout << (int)x << std::endl; std::cout << (char)y << std::endl;

¡Cualquier otra cosa no funcionará, por diseño! Entonces, esa transformación es fea, de acuerdo, pero si quieres almacenar caracteres, entonces utiliza char . No utilice bytes a menos que desee almacenar memoria sin formato que no debe interpretarse como char de forma predeterminada .

Y también la última parte de su pregunta es generalmente incorrecta: no tiene que hacer copias, porque no tiene que copiar todo el vector. Si necesita leer temporalmente un byte como un char , simplemente static_cast en el lugar donde necesita usarlo como un char . No cuesta nada, y es de tipo seguro.

En cuanto a su pregunta en el comentario sobre la conversión de std::vector<char> a std::vector<std::byte> , no puede hacer eso. Pero puedes usar la matriz cruda debajo. Entonces, lo siguiente tiene un tipo (char*) :

std::vector<std::byte> bytes; //fill it... char* charBytes = static_cast<char*>(&bytes.front());

Esto tiene el tipo char* , que es un puntero al primer elemento de su matriz, y se puede anular la referencia sin copiar, de la siguiente manera:

std::cout << charBytes[5] << std::endl; //6th element of the vector as char

Y el tamaño que obtienes de bytes.size() . Esto es válido, ya que std::vector es contiguo en la memoria. Por lo general, no puede hacer esto con ningún otro contenedor estándar (deque, lista, etc.).

Si bien esto es válido, elimina parte de la seguridad de la ecuación, tenga eso en cuenta. Si necesita char , no use byte .