Ich habe dieses kleine Juwel hier (Idee schamlos aus den C-FAQ gestohlen):
/* 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 )
Entspricht es dem neuen aktuellen Standard (C-18 zum Zeitpunkt der Beantwortung dieser Frage) (das ist kein undefiniertes Verhalten) und wenn ja, welche der älteren unterstützen es auch?
Ist es auch standardkonformes C ++? (Ja, ich weiß von std::endian
)
Antworten:
Es hat mehrere Probleme:
uint32_t
ist nicht garantiert zu existieren"ABCD"
Es ist nicht garantiert, dass ein Array, das zu einemchar*
(C) /char const*
(C ++) zerfällt, geeignet ausgerichtet istuint32_t*
. Wenn nicht, ist die Besetzung UB*(uint32_t*)"ABCD"
ist , ist deref ( ) eine strikte Aliasing-Verletzung (UB).Vielleicht möchten Sie stattdessen einfach so etwas tun:
(Funktioniert, weil
char
es existiert, Alias alles kann und minimale Ausrichtungsanforderungen hat.)Alle Makros, einschließlich Ihrer Versuche, haben den Nachteil, dass sie für Präprozessorbedingungen (
#if ...
) oder in Kontexten ungeeignet sind, in denen ein ganzzahliger konstanter Ausdruck erforderlich ist (case
Beschriftungen, Arraygrößen, Bitfeldgrößen), aber wenn sie an anderer Stelle verwendet werden, behandeln moderne Compiler im Allgemeinen die Ergebnis als Kompilierungszeitkonstante für die optimierte Baugruppenausgabe.quelle
"a character type"
ist ausdrücklich erlaubt?char*
/char const*
touint32_t*
und verwendet dieses dann für den Zugriff auf das zugrunde liegende Objekt. Es funktioniert nur umgekehrt, das heißt, wenn Sie eine habenuint32_t*
, dann können Sie es durch einen Zeichenzeiger zuzugreifen.uint32_t
selbst nicht ein Zeiger? Im Allgemeinen ist gcc sehr gut darin, eine strikte Alias-Verletzung zu kennzeichnen und punned Zeiger einzugeben, und es gibt keine Beschwerde mituint32_t u = *(uint32_t*)"ABCD";
(gcc (GCC) 9.1.0)0x01020304
hinsichtlich Middle-Endian-Plattformen, auf denen die Bytes gespeichert sind,02 01 04 03
oder03 04 01 02
?Dies ist kein definiertes Verhalten in C ++.
*(uint32_t*)"ABCD"
Behandelt die Erinnerung so,"ABCD"
als wäre es eineuint32_t
, aber da dies nicht wirklich der Fall ist, handelt es sich um eine strikte Aliasing-Verletzung und ein undefiniertes Verhalten.quelle