Gibt es eine programmgesteuerte Methode, um zu erkennen, ob Sie sich auf einer Big-Endian- oder einer Little-Endian-Architektur befinden? Ich muss in der Lage sein, Code zu schreiben, der auf einem Intel- oder PPC-System ausgeführt wird, und genau denselben Code verwenden (dh keine bedingte Kompilierung).
Programmgesteuertes Erkennen von Endianness in einem C++-Programm
Jay T
David Cournapeau
Ich mag die Methode nicht, die auf Typ-Wortspiel basiert – es wird oft vom Compiler davor gewarnt. Genau dafür sind Gewerkschaften da!
bool is_big_endian(void)
{
union {
uint32_t i;
char c[4];
} bint = {0x01020304};
return bint.c[0] == 1;
}
Das Prinzip entspricht dem von anderen vorgeschlagenen Typfall, aber dieser ist klarer – und gemäß C99 garantiert richtig. gcc bevorzugt dies gegenüber der direkten Zeigerumwandlung.
Dies ist auch viel besser, als die Endianness zur Kompilierungszeit zu korrigieren – für Betriebssysteme, die Multi-Architekturen unterstützen (z. B. Fat Binary auf Mac OS X), funktioniert dies sowohl für ppc als auch für i386, während es sonst sehr einfach ist, Dinge durcheinander zu bringen .
-
Ich empfehle nicht, eine Variable “bint” zu nennen 🙂
– Matt K
16. Juni 2009 um 13:22 Uhr
-
bist du sicher, dass das gut definiert ist? In C++ kann immer nur ein Mitglied der Union aktiv sein – dh Sie können nicht mit einem Mitgliedsnamen zuweisen und mit einem anderen lesen (obwohl es eine Ausnahme für layoutkompatible Strukturen gibt).
– Faisal Vali
16. Juni 2009 um 13:46 Uhr
-
@Matt: Ich habe in Google nachgesehen und bint scheint auf Englisch eine Bedeutung zu haben, die mir nicht bewusst war 🙂
– David Cournapeau
16. Juni 2009 um 14:34 Uhr
-
Ich habe dies getestet, und sowohl in gcc 4.0.1 als auch in gcc 4.4.1 kann das Ergebnis dieser Funktion zur Kompilierzeit bestimmt und als Konstante behandelt werden. Das bedeutet, dass der Compiler if-Zweige verwirft, die ausschließlich vom Ergebnis dieser Funktion abhängen und niemals auf der betreffenden Plattform ausgeführt werden. Dies gilt wahrscheinlich nicht für viele Implementierungen von htonl.
– Allmächtig
10. September 2009 um 5:25 Uhr
-
Ist diese Lösung wirklich portabel? Was, wenn
CHAR_BIT != 8
?– zorgit
30. Mai 2015 um 20:12 Uhr
Sie können verwenden std::endian
wenn Sie Zugriff auf C++20-Compiler wie GCC 8+ oder Clang 7+ haben.
Notiz: std::endian
begann in <type_traits>
aber wurde bewegt zu <bit>
beim Kölner Treffen 2019. GCC 8, Clang 7, 8 und 9 haben es in sich <type_traits>
während GCC 9+ und Clang 10+ es haben <bit>
.
#include <bit>
if constexpr (std::endian::native == std::endian::big)
{
// Big endian system
}
else if constexpr (std::endian::native == std::endian::little)
{
// Little endian system
}
else
{
// Something else
}
-
Wie jeder habe ich Zugriff auf C++17- und 20-Entwürfe/Vorschläge, aber existiert ab sofort jemals ein C++20-Compiler?
– Xeverous
29. Oktober 2017 um 21:35 Uhr
-
@Xeverous Es erfordert nur bereichsbezogene Enumerationen, daher vermute ich, dass die meisten Anbieter es als eine ihrer früheren Änderungen zu ihrer stdlib-Implementierung hinzufügen werden.
– Pharap
25. März 2018 um 3:53 Uhr
-
@Xeverous GCC 8 wurde veröffentlicht und unterstützt es.
– Benutzer3624760
8. Mai 2018 um 8:38 Uhr
-
Von den mehr als 30 Antworten auf die Frage scheint dies die einzige zu sein, die völlig korrekt ist (mit einer anderen Antwort, die zumindest teilweise richtig ist).
– Inspektionsfähig
1. Januar 2020 um 22:43 Uhr
Eric Petroelje
Sie können dies tun, indem Sie ein int setzen und Bits maskieren, aber wahrscheinlich ist der einfachste Weg, einfach die eingebauten Netzwerk-Byte-Konvertierungsoperationen zu verwenden (da die Netzwerk-Byte-Reihenfolge immer Big Endian ist).
if ( htonl(47) == 47 ) {
// Big endian
} else {
// Little endian.
}
Das Fummeln könnte schneller sein, aber dieser Weg ist einfach, unkompliziert und ziemlich unmöglich zu vermasseln.
-
Die Netzwerkkonvertierungsoperationen können auch verwendet werden, um alles in Big Endian zu konvertieren und so andere Probleme zu lösen, auf die Jay möglicherweise stößt.
– Brian
16. Juni 2009 um 13:15 Uhr
-
@sharptooth – langsam ist ein relativer Begriff, aber ja, wenn Geschwindigkeit wirklich ein Problem ist, verwenden Sie ihn einmal am Start des Programms und setzen Sie eine globale Variable mit der Endianness.
– Eric Petroelje
16. Juni 2009 um 13:23 Uhr
-
htonl hat ein weiteres Problem: Auf einigen Plattformen (Windows ?) befindet es sich nicht in der eigentlichen C-Laufzeitbibliothek, sondern in zusätzlichen, netzwerkbezogenen Bibliotheken (Socket usw.). Dies ist für nur eine Funktion ziemlich hinderlich, wenn Sie die Bibliothek sonst nicht benötigen.
– David Cournapeau
7. Juli 2009 um 5:00 Uhr
-
Beachten Sie, dass htonl unter Linux (gcc) zur Kompilierzeit einer konstanten Faltung unterliegt, sodass ein Ausdruck dieser Form überhaupt keinen Laufzeit-Overhead hat (dh er wird konstant auf 1 oder 0 gefaltet, und dann entfernt die Eliminierung von totem Code die anderer Zweig des if)
– bdonlan
6. Dezember 2011 um 20:16 Uhr
-
Außerdem kann htonl auf x86 sehr effizient mit Inline-Assembler implementiert werden (und wird es auf Linux/gcc), insbesondere wenn Sie auf eine Mikroarchitektur mit Unterstützung für das abzielen
BSWAP
Operation.– bdonlan
6. Dezember 2011 um 20:18 Uhr
Bitte sehen Dieser Beitrag:
Hier ist ein Code, um zu bestimmen, was der Typ Ihrer Maschine ist
int num = 1; if(*(char *)&num == 1) { printf("\nLittle-Endian\n"); } else { printf("Big-Endian\n"); }
Dies geschieht normalerweise zur Kompilierzeit (insbesondere aus Leistungsgründen), indem Sie die vom Compiler verfügbaren Header-Dateien verwenden oder Ihre eigenen erstellen. Unter Linux haben Sie die Header-Datei “/usr/include/endian.h”
-
Ich kann nicht glauben, dass dies nicht höher gestimmt wurde. Es ist nicht so, dass sich die Endianness unter einem kompilierten Programm ändern wird, daher ist kein Laufzeittest erforderlich.
– Dolda2000
3. September 2014 um 9:59 Uhr
-
@ Dolda2000 Es könnte möglicherweise die ARM-Endian-Modi anzeigen.
– Tyzoid
10. März 2016 um 21:50 Uhr
-
@Tyzoid: Nein, ein kompiliertes Programm wird immer im Endian-Modus ausgeführt, für den es kompiliert wurde, auch wenn der Prozessor beides kann.
– Dolda2000
11. März 2016 um 0:42 Uhr
DaveR
Ich bin überrascht, dass niemand die Makros erwähnt hat, die der Präprozessor standardmäßig definiert. Diese variieren zwar je nach Plattform; sie sind viel sauberer, als einen eigenen Endian-Check schreiben zu müssen.
Zum Beispiel; wenn wir uns die eingebauten Makros ansehen, die GCC definiert (auf einem X86-64-Rechner):
:| gcc -dM -E -x c - |grep -i endian
#define __LITTLE_ENDIAN__ 1
Auf einer PPC-Maschine bekomme ich:
:| gcc -dM -E -x c - |grep -i endian
#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1
(Die :| gcc -dM -E -x c -
magic druckt alle eingebauten Makros).
-
Ich kann nicht glauben, dass dies nicht höher gestimmt wurde. Es ist nicht so, dass sich die Endianness unter einem kompilierten Programm ändern wird, daher ist kein Laufzeittest erforderlich.
– Dolda2000
3. September 2014 um 9:59 Uhr
-
@ Dolda2000 Es könnte möglicherweise die ARM-Endian-Modi anzeigen.
– Tyzoid
10. März 2016 um 21:50 Uhr
-
@Tyzoid: Nein, ein kompiliertes Programm wird immer im Endian-Modus ausgeführt, für den es kompiliert wurde, auch wenn der Prozessor beides kann.
– Dolda2000
11. März 2016 um 0:42 Uhr
Deklarieren Sie eine int-Variable:
int variable = 0xFF;
Verwenden Sie nun char*-Zeiger auf verschiedene Teile davon und prüfen Sie, was in diesen Teilen enthalten ist.
char* startPart = reinterpret_cast<char*>( &variable );
char* endPart = reinterpret_cast<char*>( &variable ) + sizeof( int ) - 1;
Je nachdem, welches auf das 0xFF-Byte zeigt, können Sie jetzt Endianness erkennen. Dies erfordert sizeof( int ) > sizeof( char ), aber es gilt definitiv für die besprochenen Plattformen.
Der Vollständigkeit halber ist hier ein Link zu der Frage eines anderen über den Versuch, die Endianness (zur Kompilierzeit) zu messen: stackoverflow.com/questions/280162/…
– Faisal Vali
16. Juni 2009 um 13:52 Uhr
Warum nicht die Endianness zur Kompilierzeit bestimmen? Es kann unmöglich zur Laufzeit geändert werden.
– vergänglich
20. Juni 2009 um 20:31 Uhr
AFAIK, dafür gibt es keinen zuverlässigen und universellen Weg. gcc.gnu.org/ml/gcc-help/2007-07/msg00342.html
– Benutzer48956
13. August 2010 um 21:35 Uhr