Makrodefinition zur Ermittlung von Big-Endian- oder Little-Endian-Maschine?
Lesezeit: 8 Minuten
manav mn
Gibt es eine einzeilige Makrodefinition, um die Endianness der Maschine zu bestimmen? Ich verwende den folgenden Code, aber das Konvertieren in ein Makro wäre zu lang:
Sie können die Endianness nicht allein mit dem C-Präprozessor portabel bestimmen. Sie wollen auch 0 Anstatt von NULL in Ihrem Abschlusstest, und ändern Sie eine der test_endian Objekte zu etwas anderem :-).
– Alok Singhal
20. Januar 2010 um 9:48 Uhr
Und warum ist ein Makro notwendig? Die Inline-Funktion würde dasselbe tun und ist viel sicherer.
– scharfer Zahn
20. Januar 2010 um 9:49 Uhr
@Sharptooth, ein Makro ist ansprechend, weil sein Wert zur Kompilierzeit bekannt sein kann, was bedeutet, dass Sie die Endianness Ihrer Plattform verwenden können, um beispielsweise die Vorlageninstanziierung zu steuern, oder vielleicht sogar verschiedene Codeblöcke mit einem auswählen können #if Richtlinie.
– Rob Kennedy
8. April 2010 um 5:08 Uhr
Das stimmt, aber ineffizient. Wenn ich eine Little-Endian-CPU habe und Little-Endian-Daten in die Leitung oder in eine Datei schreibe, würde ich es lieber vermeiden, Daten sinnlos zu entpacken und neu zu packen. Früher habe ich beruflich Videotreiber geschrieben. es ist äußerst wichtig beim Schreiben von Pixeln auf eine Grafikkarte, um jeden Ort zu optimieren, an dem Sie können.
– Eduard Falk
5. September 2016 um 16:26 Uhr
Christoph
Code, der willkürliche Byte-Reihenfolgen unterstützt und bereit ist, in eine Datei namens abgelegt zu werden order32.h:
Sie würden über nach Little-Endian-Systemen suchen
O32_HOST_ORDER == O32_LITTLE_ENDIAN
Das lässt dich nicht sich entscheiden Endian-ness bis zur Laufzeit. Folgendes kann nicht kompiliert werden, weil. /** isLittleEndian::result –> 0 oder 1 */ struct isLittleEndian { enum isLittleEndianResult { result = (O32_HOST_ORDER == O32_LITTLE_ENDIAN) }; };
– Benutzer48956
13. August 2010 um 17:54 Uhr
Ist es unmöglich, das Ergebnis bis zur Laufzeit zu erhalten?
– k06a
26. Dezember 2010 um 12:03 Uhr
Warum char? Besser verwenden uint8_t und schlagen fehl, wenn dieser Typ nicht verfügbar ist (was überprüft werden kann durch #if UINT8_MAX). Beachten Sie, dass CHAR_BIT ist unabhängig von uint8_t.
– Andreas Spindler
31. Oktober 2012 um 11:33 Uhr
Dies ist UB in c++: stackoverflow.com/questions/11373203/…
– Benutzer3624760
1. Juli 2016 um 8:55 Uhr
Lassen Sie mich der Vollständigkeit halber noch einen in die Mischung werfen: O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 */
– Eduard Falk
5. September 2016 um 17:10 Uhr
Café
Wenn Sie einen Compiler haben, der zusammengesetzte C99-Literale unterstützt:
“Sie sollten versuchen, Code zu schreiben, der nicht von der Endianness der Host-Plattform abhängt”. Leider stieß mein Appell “Ich weiß, dass wir eine POSIX-Kompatibilitätsschicht schreiben, aber ich möchte ntoh nicht implementieren, weil es von der Endianness der Host-Plattform abhängt” immer auf taube Ohren gestoßen ;-). Die Verarbeitung von Grafikformaten und Konvertierungscode ist der andere Hauptkandidat, den ich gesehen habe – Sie möchten nicht alles darauf stützen, ständig ntohl anzurufen.
– Steve Jessop
20. Januar 2010 um 13:03 Uhr
Sie können umsetzen ntohl auf eine Weise, die nicht von der Endianness der Host-Plattform abhängt.
– Café
20. Januar 2010 um 13:13 Uhr
@caf wie würdest du ntohl auf host-endianness-unabhängige Weise schreiben?
– Hayri Uğur Koltuk
1. März 2012 um 12:39 Uhr
@AliVeli: Ich habe der Antwort eine Beispielimplementierung hinzugefügt.
– Café
1. März 2012 um 21:12 Uhr
Ich sollte auch fürs Protokoll hinzufügen, dass “(*(uint16_t *)”\0\xff” < 0x100)" nicht in eine Konstante kompiliert wird, egal wie viel ich optimiere, zumindest mit gcc 4.5.2. Es erstellt immer ausführbaren Code.
– Eduard Falk
11. Juli 2012 um 20:29 Uhr
Es gibt keinen Standard, aber auf vielen Systemen darunter <endian.h> gibt Ihnen einige Definitionen, nach denen Sie suchen können.
Testen Sie die Endianness mit #if __BYTE_ORDER == __LITTLE_ENDIAN und #elif __BYTE_ORDER == __BIG_ENDIAN. Und erzeuge ein #error sonst.
In OpenBSD 6.3 stellt bereit #if BYTE_ORDER == LITTLE_ENDIAN(oder BIG_ENDIAN) ohne Unterstriche vor den Namen. _BYTE_ORDER ist nur für Systemkopfzeilen. __BYTE_ORDER ist nicht vorhanden.
– Georg Köhler
6. April 2018 um 4:11 Uhr
@To1ne Ich bezweifle, dass Endianness für Windows relevant ist, da Windows (zumindest derzeit) nur auf x86- und ARM-Computern läuft. x86 ist immer LE und ARM ist konfigurierbar, um beide Architekturen zu verwenden.
– SimonC
19. Dezember 2018 um 8:13 Uhr
Um Endianness zur Laufzeit zu erkennen, müssen Sie in der Lage sein, auf den Speicher zu verweisen. Wenn Sie sich an Standard-C halten, erfordert die Deklaration einer Variablen im Speicher eine Anweisung, aber die Rückgabe eines Werts erfordert einen Ausdruck. Ich weiß nicht, wie ich das in einem einzelnen Makro machen soll – deshalb hat gcc Erweiterungen 🙂
Wenn Sie bereit sind, eine .h-Datei zu haben, können Sie diese definieren
und dann kannst du die verwenden ENDIANNESS Makro wie Sie wollen.
Gregor Pakosz
Wenn Sie sich nur auf den Präprozessor verlassen wollen, müssen Sie die Liste der vordefinierten Symbole herausfinden. Präprozessor-Arithmetik hat kein Adressierungskonzept.
GCC auf Mac definiert __LITTLE_ENDIAN__ oder __BIG_ENDIAN__
Dann können Sie weitere bedingte Präprozessor-Direktiven basierend auf der Plattformerkennung wie hinzufügen #ifdef _WIN32 usw.
GCC 4.1.2 unter Linux scheint diese Makros nicht zu definieren, obwohl GCC 4.0.1 und 4.2.1 sie auf Macintosh definieren. Es ist also keine zuverlässige Methode für die plattformübergreifende Entwicklung, selbst wenn Sie bestimmen dürfen, welcher Compiler verwendet werden soll.
– Rob Kennedy
8. April 2010 um 3:02 Uhr
Oh ja, es liegt daran, dass es nur von GCC auf dem Mac definiert wird.
clang 5.0.1 für OpenBSD/amd64 hat #define __LITTLE_ENDIAN__ 1. Dieses Makro scheint eine Clang-Funktion zu sein, keine gcc-Funktion. Das gcc Der Befehl auf einigen Macs ist nicht gcc, sondern clang.
– Georg Köhler
6. April 2018 um 4:05 Uhr
GCC 4.2.1 auf Mac war damals GCC
– Gregory Pakosz
6. April 2018 um 11:30 Uhr
ggpp23
Ich glaube, danach wurde gefragt. Ich habe dies nur auf einer kleinen Endian-Maschine unter msvc getestet. Jemand bestätigt bitte auf einer Big-Endian-Maschine.
#define LITTLE_ENDIAN 0x41424344UL
#define BIG_ENDIAN 0x44434241UL
#define PDP_ENDIAN 0x42414443UL
#define ENDIAN_ORDER ('ABCD')
#if ENDIAN_ORDER==LITTLE_ENDIAN
#error "machine is little endian"
#elif ENDIAN_ORDER==BIG_ENDIAN
#error "machine is big endian"
#elif ENDIAN_ORDER==PDP_ENDIAN
#error "jeez, machine is PDP!"
#else
#error "What kind of hardware is this?!"
#endif
Als Nebenbemerkung (Compiler-spezifisch) können Sie mit einem aggressiven Compiler die Optimierung “Dead Code Elimination” verwenden, um den gleichen Effekt wie eine Kompilierzeit zu erzielen #if so:
unsigned yourOwnEndianSpecific_htonl(unsigned n)
{
static unsigned long signature= 0x01020304UL;
if (1 == (unsigned char&)signature) // big endian
return n;
if (2 == (unsigned char&)signature) // the PDP style
{
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
if (4 == (unsigned char&)signature) // little endian
{
n = (n << 16) | (n >> 16);
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
// only weird machines get here
return n; // ?
}
Das Obige beruht auf der Tatsache, dass der Compiler die konstanten Werte zur Kompilierzeit erkennt und den darin enthaltenen Code vollständig entfernt if (false) { ... } und ersetzt Code wie if (true) { foo(); } mit foo(); Das Worst-Case-Szenario: Der Compiler führt die Optimierung nicht durch, Sie erhalten immer noch korrekten Code, aber etwas langsamer.
GCC 4.1.2 unter Linux scheint diese Makros nicht zu definieren, obwohl GCC 4.0.1 und 4.2.1 sie auf Macintosh definieren. Es ist also keine zuverlässige Methode für die plattformübergreifende Entwicklung, selbst wenn Sie bestimmen dürfen, welcher Compiler verwendet werden soll.
– Rob Kennedy
8. April 2010 um 3:02 Uhr
Oh ja, es liegt daran, dass es nur von GCC auf dem Mac definiert wird.
clang 5.0.1 für OpenBSD/amd64 hat #define __LITTLE_ENDIAN__ 1. Dieses Makro scheint eine Clang-Funktion zu sein, keine gcc-Funktion. Das gcc Der Befehl auf einigen Macs ist nicht gcc, sondern clang.
– Georg Köhler
6. April 2018 um 4:05 Uhr
GCC 4.2.1 auf Mac war damals GCC
– Gregory Pakosz
6. April 2018 um 11:30 Uhr
Jérôme Pouiller
Wenn Sie nach einem Kompilierzeittest suchen und gcc verwenden, können Sie Folgendes tun:
Warum nicht denselben Code in ein Makro einfügen?
– scharfer Zahn
20. Januar 2010 um 9:46 Uhr
Sie können die Endianness nicht allein mit dem C-Präprozessor portabel bestimmen. Sie wollen auch
0
Anstatt vonNULL
in Ihrem Abschlusstest, und ändern Sie eine dertest_endian
Objekte zu etwas anderem :-).– Alok Singhal
20. Januar 2010 um 9:48 Uhr
Und warum ist ein Makro notwendig? Die Inline-Funktion würde dasselbe tun und ist viel sicherer.
– scharfer Zahn
20. Januar 2010 um 9:49 Uhr
@Sharptooth, ein Makro ist ansprechend, weil sein Wert zur Kompilierzeit bekannt sein kann, was bedeutet, dass Sie die Endianness Ihrer Plattform verwenden können, um beispielsweise die Vorlageninstanziierung zu steuern, oder vielleicht sogar verschiedene Codeblöcke mit einem auswählen können
#if
Richtlinie.– Rob Kennedy
8. April 2010 um 5:08 Uhr
Das stimmt, aber ineffizient. Wenn ich eine Little-Endian-CPU habe und Little-Endian-Daten in die Leitung oder in eine Datei schreibe, würde ich es lieber vermeiden, Daten sinnlos zu entpacken und neu zu packen. Früher habe ich beruflich Videotreiber geschrieben. es ist äußerst wichtig beim Schreiben von Pixeln auf eine Grafikkarte, um jeden Ort zu optimieren, an dem Sie können.
– Eduard Falk
5. September 2016 um 16:26 Uhr