Tengo esta pequeña joya aquí (idea robada descaradamente de las preguntas frecuentes de C):
/* 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 )
¿Cumple (no es un comportamiento indefinido) con el nuevo estándar actual (C-18 en el momento en que se hizo esta pregunta) y, en caso afirmativo, cuál de los más antiguos también lo admite?
¿Es también estándar compatible con C ++? (Sí, lo sé std::endian
)
Respuestas:
Tiene varios problemas:
uint32_t
no se garantiza que exista"ABCD"
, no se garantiza que una matriz en descomposición achar*
(C) /char const*
(C ++) esté alineada adecuadamenteuint32_t*
. Si no es así, el elenco es UB*(uint32_t*)"ABCD"
) es una violación de alias estricta (UB)Es posible que desee hacer algo como esto en su lugar:
(Funciona porque
char
existirá, puede alias cualquier cosa y tiene requisitos mínimos de alineación).Todas las macros, incluidos sus intentos, tienen la desventaja de ser inadecuadas para los condicionales del preprocesador (
#if ...
) o en contextos donde se requiere una expresión constante entera (case
etiquetas, tamaños de matriz, tamaños de campo de bits), pero cuando se usan en otros lugares, los compiladores modernos generalmente tratan el resultado como una constante de tiempo de compilación en lo que respecta a la salida de ensamblaje optimizadafuente
"a character type"
está específicamente permitido?char*
/char const*
auint32_t*
y luego lo usa para acceder al objeto subyacente. Sólo funciona al revés, es decir, cuando tiene unauint32_t*
, entonces se puede acceder a él a través de un puntero de carácter.uint32_t
sí mismo y no un puntero? En general, gcc es muy bueno para señalar una violación estricta de alias y escribir punteros punteados, y no hay ninguna queja conuint32_t u = *(uint32_t*)"ABCD";
(gcc (GCC) 9.1.0)0x01020304
las plataformas intermedias que almacenan los bytes02 01 04 03
o03 04 01 02
?Este no es un comportamiento definido en C ++.
*(uint32_t*)"ABCD"
trata la memoria de"ABCD"
como si fuera unuint32_t
, pero como no lo es realmente, esta es una violación de alias estricta y un comportamiento indefinido.fuente