En su reciente charla "Punking de tipo en C ++ moderno", Timur Doumler dijo que std::bit_cast
no se puede usar para convertir un bit float
en un unsigned char[4]
porque las matrices de estilo C no se pueden devolver de una función. Deberíamos usar std::memcpy
o esperar hasta C ++ 23 (o posterior) cuando algo así reinterpret_cast<unsigned char*>(&f)[i]
esté bien definido.
En C ++ 20, ¿podemos usar un std::array
con std::bit_cast
,
float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
en lugar de una matriz de estilo C para obtener bytes de a float
?
fuente
struct X { unsigned char elems[5]; };
satisface la regla que está citando. Ciertamente se puede inicializar en una lista con hasta 4 elementos. Puede también ser inicializado lista con los 5 elementos. No creo que ningún implementador de biblioteca estándar odie a las personas lo suficiente como para hacer esto, pero creo que es técnicamente conforme.elems[5]
. Y en ese punto no puedo ver cómo podrías terminar con un agregadosizeof(array<char, sizeof(T)>) != sizeof(T)
¿ dónde ?struct X { unsigned char c1, c2, c3, c4; };
ostruct X { unsigned char elems[4]; };
, por lo tanto, aunque los caracteres deben ser los elementos de ese agregado, esto les permite ser elementos agregados directos o elementos de un solo sub-agregado.P -> Q
no implica nada sobre el caso donde!P
array
no tenga relleno. Las implementaciones de este pueden no tener relleno (y cualquier implementación que lo haga debe considerarse disfuncional), pero no hay garantía de que enarray
sí no lo tenga.La respuesta aceptada es incorrecta porque no tiene en cuenta los problemas de alineación y relleno.
Por [matriz] / 1-3 :
El estándar en realidad no requiere
std::array
tener exactamente un miembro de datos público de tipoT[N]
, por lo que en teoría es posible quesizeof(To) != sizeof(From)
ois_trivially_copyable_v<To>
.Sin embargo, me sorprendería si esto no funciona en la práctica.
fuente
Si.
Según el documento que describe el comportamiento
std::bit_cast
y la implementación propuesta en la medida en que ambos tipos tengan el mismo tamaño y se puedan copiar trivialmente, el reparto debe ser exitoso.Una implementación simplificada de
std::bit_cast
debería ser algo como:Desde un flotante (4 bytes) y una matriz de
unsigned char
consize_of(float)
respecto a todas esas afirmaciones, se realizará el subyacentestd::memcpy
. Por lo tanto, cada elemento en la matriz resultante será un byte consecutivo del flotante.Para probar este comportamiento, escribí un pequeño ejemplo en Compiler Explorer que puedes probar aquí: https://godbolt.org/z/4G21zS . El float 5.0 se almacena correctamente como una matriz de bytes (
Ox40a00000
) que corresponde a la representación hexadecimal de ese número flotante en Big Endian .fuente
std::array
está garantizado que no tiene bits de relleno, etc.?auto bits = reinterpret_cast<std::array<unsigned char, sizeof(float)>&>(f)
y obtener exactamente la misma salida. ¿Prueba algo?std::array
satisface los requisitos de ContiguiosContainer (desde C ++ 17) .std::vector
también satisface los mismos criterios y obviamente no se puede usar aquí. ¿Hay algo que requiera questd::array
mantenga los elementos dentro de la clase (en un campo), evitando que sea un puntero simple a la matriz interna? (como en vector, que también tiene un tamaño, que matriz no requiere tener en un campo)std::array
efectivamente requiere que almacene los elementos dentro, pero me preocupan los problemas de diseño.