Programmgesteuertes Erkennen von Endianness in einem C++-Programm

Lesezeit: 6 Minuten

Programmgesteuertes Erkennen von Endianness in einem C Programm
Jay T

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).

  • 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

Programmgesteuertes Erkennen von Endianness in einem C Programm
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

Programmgesteuertes Erkennen von Endianness in einem C Programm
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

1647145210 412 Programmgesteuertes Erkennen von Endianness in einem C Programm
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.

995910cookie-checkProgrammgesteuertes Erkennen von Endianness in einem C++-Programm

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy