Eu tenho essa pequena jóia aqui (idéia descaradamente roubada do C-FAQ):
/* A lot of checks omitted to get rid of the architectures with a "weird" endianness */
/*...*/
#define MP_ENDIANESS ( (0x41424344ul == *(uint32_t*)"ABCD") ? MP_BIG_ENDIAN : MP_LITTLE_ENDIAN )
É compatível (que não é um comportamento indefinido) com o novo padrão atual (C-18 no momento em que essa pergunta foi feita) e, se sim, quais dos mais antigos também o apoiam?
Também é compatível com C ++ padrão? (Sim, eu sei sobre std::endian
)
Respostas:
Tem vários problemas:
uint32_t
não é garantido que exista"ABCD"
, não é garantido que um array decadente parachar*
(C) /char const*
(C ++) esteja alinhado adequadamenteuint32_t*
. Se não for, o elenco é UB*(uint32_t*)"ABCD"
) é uma violação estrita de alias (UB)Você pode simplesmente fazer algo assim:
(Funciona porque
char
existirá, pode alternar entre qualquer coisa e possui requisitos mínimos de alinhamento.)Todas as macros, incluindo suas tentativas, têm a desvantagem de serem inadequadas para condicionais de pré-processador (
#if ...
) ou em contextos em que é necessária uma expressão constante inteira (case
rótulos, tamanhos de matriz, tamanhos de campo de bits), mas, quando usados em outros lugares, os compiladores modernos geralmente tratam o problema. resultado como uma constante de tempo de compilação no que diz respeito à saída otimizada da montagem.fonte
"a character type"
é especificamente permitido?char*
/char const*
parauint32_t*
e usando-o para acessar o objeto subjacente. Ele só funciona vice-versa, ou seja, quando você tem umuint32_t*
, então você pode acessá-lo através de um ponteiro de caracteres.uint32_t
si mesmo não são um ponteiro? Geralmente gcc é muito bom em sinalizar um rigoroso apelido violação e digite ponteiros punned, e não há nenhuma queixauint32_t u = *(uint32_t*)"ABCD";
(gcc (GCC) 9.1.0)0x01020304
com as plataformas da Middleian que armazenam os bytes02 01 04 03
ou03 04 01 02
?Esse não é um comportamento definido no C ++.
*(uint32_t*)"ABCD"
trata a memória"ABCD"
como se fosse umauint32_t
, mas como não é realmente, trata-se de uma violação estrita de alias e um comportamento indefinido.fonte