Em sua recente palestra “Type punping in C ++ moderno”, Timur Doumler disse que std::bit_cast
não pode ser usado para converter um bit float
em um, unsigned char[4]
porque matrizes no estilo C não podem ser retornadas de uma função. Devemos usar std::memcpy
ou aguardar até C ++ 23 (ou mais recente) quando algo assim reinterpret_cast<unsigned char*>(&f)[i]
se tornar bem definido.
Em C ++ 20, podemos usar um std::array
com std::bit_cast
,
float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
em vez de uma matriz de estilo C para obter bytes de um float
?
fonte
struct X { unsigned char elems[5]; };
satisfaz a regra que você está citando. Certamente pode ser inicializado em lista com até 4 elementos. Ele pode também ser com 5 elementos inicializado-list. Eu não acho que nenhum implementador de biblioteca padrão odeie pessoas o suficiente para fazer isso, mas acho que é tecnicamente compatível.elems[5]
. E, nesse ponto, não vejo como você pode acabar agregando ondesizeof(array<char, sizeof(T)>) != sizeof(T)
?struct X { unsigned char c1, c2, c3, c4; };
ou outrostruct X { unsigned char elems[4]; };
- embora os caracteres precisem ser os elementos desse agregado, isso permite que sejam elementos agregados diretos ou elementos de um único subagregado.P -> Q
não implica nada sobre o caso em que!P
array
ele próprio não terá preenchimento. As implementações dele podem não ter preenchimento (e quaisquer implementações que o façam devem ser consideradas disfuncionais), mas não há garantia de quearray
ele não tenha.A resposta aceita está incorreta porque não considera os problemas de alinhamento e preenchimento.
Por [matriz] / 1-3 :
Na verdade, o padrão não requer
std::array
exatamente um membro de dados públicos do tipoT[N]
; portanto, em teoria, é possível quesizeof(To) != sizeof(From)
ouis_trivially_copyable_v<To>
.Ficarei surpreso se isso não funcionar na prática.
fonte
Sim.
De acordo com o artigo que descreve o comportamento de
std::bit_cast
, e sua implementação proposta , na medida em que ambos os tipos têm o mesmo tamanho e são trivialmente copiáveis, o elenco deve ser bem-sucedido.Uma implementação simplificada de
std::bit_cast
deve ser algo como:Como um float (4 bytes) e uma matriz
unsigned char
comsize_of(float)
respeito a todas essas afirmações, o subjacentestd::memcpy
será executado. Portanto, cada elemento na matriz resultante será um byte consecutivo do float.Para provar esse comportamento, escrevi um pequeno exemplo no Compiler Explorer que você pode tentar aqui: https://godbolt.org/z/4G21zS . O flutuador 5.0 é armazenado corretamente como uma matriz de bytes (
Ox40a00000
) que corresponde à representação hexadecimal desse número flutuante no Big Endian .fonte
std::array
não há bits de preenchimento, etc.?auto bits = reinterpret_cast<std::array<unsigned char, sizeof(float)>&>(f)
e obter exatamente a mesma saída. Isso prova alguma coisa?std::array
atende aos requisitos do ContiguiosContainer (desde C ++ 17) .std::vector
também atende aos mesmos critérios e obviamente não pode ser usado aqui. Existe algo exigindo questd::array
mantenha os elementos dentro da classe (em um campo), impedindo que ele seja um ponteiro simples para a matriz interna? (como no vector, o que também tem um tamanho, o qual matriz não necessita de ter em um campo)std::array
efetivamente exige que ele armazene os elementos internos, mas estou preocupado com problemas de layout.