2011-01-17 26 views
1

(Diese Frage kam aus die Details CHAR_BIT erklären, sizeof und endianness jemand gestern. Es völlig hypothetisch ist.)Wie erkenne ich Endianess auf einem System, auf dem alle primitiven Integer-Größen gleich sind?

Lasst uns sagen, dass ich auf einer Plattform bin, wo CHAR_BIT 32 ist, so sizeof (char) = = sizeof (kurz) == sizeof (int) == sizeof (lang). Ich glaube, dass dies immer noch eine standardkonforme Umgebung ist.

Der üblicher Weg endianness zur Laufzeit (because there is no reliable way to do it at compile time) zu erkennen ist, ein union { int i, char c[sizeof(int)] } x; x.i = 1 zu machen und sehen, ob x.c[0] oder x.c[sizeof(int)-1] eingestellt wurde.

Aber das funktioniert nicht auf dieser Plattform, da ich am Ende mit einem char [1] enden.

Gibt es eine Möglichkeit zu erkennen, ob eine solche Plattform zur Laufzeit big-endian oder little-endian ist? Offensichtlich spielt es in diesem hypothetischen System keine Rolle, aber man kann sich vorstellen, dass es in eine Datei schreibt oder in eine Art Speicherbereich, die von einer anderen Maschine entsprechend ihrem (gesünderen) Speichermodell gelesen und rekonstruiert wird.

+0

können Sie versuchen, das 'AC_C_BIGENDIAN'-Makro von autoconf zur Kompilierzeit zu verwenden, es ist ziemlich robust und greift auf eine Test-Binärdatei zurück, wenn es den Code nicht direkt ausführen kann. – Hasturkun

Antwort

4

Das Konzept der endianness macht nur Sinn für skalare Typen von mehreren Bytes dargestellt. Per Definition ist ein char Einzelbyte, so dass jeder ganzzahlige Typ mit der gleichen Größe wie char keine Endianness hat.

Denken Sie auch daran, dass die Endianness für verschiedene Typen unterschiedlich sein kann: Zum Beispiel ist der PDP-11 eine Little-Endian-16-Bit-Architektur und 32-Bit-Integer werden aus zwei 16-Bit-Little-Endian-Werten gebildet , endet gemischt Endian.

+0

Ihr Kommentar zu Martins Antwort scheint mir die beste Erklärung zu sein. Die Endianz in diesem System hat nur dann Bedeutung, wenn wir sie in ein anderes System übersetzen müssen - was auch immer dieser Übersetzungsschritt ist, kann nicht in derselben C-Umgebung geschrieben werden - ergo ist die Frage für diese Plattform bedeutungslos, auch wenn Die Bytes/Bits haben eine gewisse Reihenfolge, die die Übersetzungsschicht überprüfen kann. –

+0

endianness (aka byte order) ist ein Konzept unabhängig von der Idee der Oktette - historisch, Bytes kommen in verschiedenen Größen (4-Bit-BCD, 6-Bit-Grafik-Set, 16-Bit-DSPs), und noch heute gibt es spezielle Zwecke Geräte mit 'CHAR_BIT! = 8'; Solange es Multibyte-Skalartypen gibt, ist die Endianheit ein wohldefiniertes Konzept; Serialisierung auf 8-Bit-Geräte ist aus dieser Sicht irrelevant – Christoph

2

Ich nehme an, die Frage läuft auf: Ist Endianess sogar ein sinnvolles Konzept auf dieser Plattform, d. H. Hat es einen nachweisbaren Einfluss auf das Verhalten eines Programms?

Ist dies nicht der Fall, dann ist Endianness (dh die Reihenfolge, in der die einzelnen Bytes einer 32-Bit-Menge gespeichert werden) lediglich ein Implementierungsdetail, das Sie nicht erkennen können, aber nicht benötigen dich auch nicht kümmern.

Wenn Endianness einen nachweisbaren Einfluss auf das Verhalten eines bestimmten Aspekts der Sprache hat ... nun, dann konstruiere einen Test, der auf diesem Verhalten basiert. Hier einige Beispiele:

  • Wie funktioniert das Adressierungssystem auf der Plattform? Wenn Sie eine Adresse um eins erhöhen, wie viele Bits entspricht das? Wenn die Antwort acht Bits beträgt und das System Ihnen erlaubt, Adressen zu lesen, die kein Vielfaches von vier sind, können Sie einen Zeiger um ein einzelnes Byte vorwärts bewegen (über einen Umweg zu intptr_t) und auf diese Weise auf Endianess testen. (Ja, das ist implementationsdefiniertes Verhalten, aber es wird auch eine Union verwendet, um sowohl auf Endianess als auch auf das gesamte Konzept der Endianz im Allgemeinen zu testen.) Wenn jedoch die kleinste adressierbare Speichereinheit 32 Bytes ist, dann können Sie t teste auf diese Weise nach endianess.

  • Hat die Plattform einen 64-Bit-Datentyp (a long long)? Dann können Sie eine Vereinigung von long long und zwei int s erstellen und daraus Ihren Endianness-Test erstellen.

+0

Natürlich können Sie es erkennen. Setzen Sie eine 2-Byte-Ganzzahl auf 1 und sehen Sie, welches der Bytes nicht Null ist. –

+0

>> Nehmen wir an, ich bin auf einer Plattform, wo CHAR_BIT 32 ist, also sizeof (char) == sizeof (kurz) == sizeof (int) == sizeof (lang). Ich glaube, das ist immer noch eine standardkonforme Umgebung. << Das Byte/Zeichen ist genau so groß wie eine Ganzzahl. – bestsss

+0

@ David Heffernan> Sie können kein "Byte" sehen. In dieser C-Umgebung gibt es keine "Bytes". :-) –

4

Hypothetisch, in einer Umgebung, in der alle Datentypen die gleiche Größe haben, gibt es keine Endianess.

kann ich drei Möglichkeiten für Sie sehen:

  • Wenn die Beschränkung nur durch C-Compiler gegeben ist und technisch die Plattform hat einige kleinere Datentypen können Sie Assembler verwenden Endianess zu erkennen.

  • Wenn die Plattform den doppelten Datentyp unterstützt, können Sie damit die Endanfälligkeit erkennen, da sie immer 64 Bit breit ist.

  • Sie können auch Daten in die Datei schreiben, wie Sie vorgeschlagen haben, und dann zurückgelesen. Schreiben Sie einfach zwei Zeichen (Datei im Binärmodus), verschieben Sie den Dateizeiger auf Position 1 und lesen Sie ein Zeichen zurück.

+0

>> Sie können auch Daten in die Datei schreiben, wie Sie vorgeschlagen haben, und dann zurücklesen. ... nicht sicher, wie das implementiert werden würde, wenn das System keine Möglichkeit hat, irgendetwas unter 32 Bits zu adressieren.Mein Verständnis über ein solches System ist, dass ein Byte tatsächlich 32bits ist und die Dateiposition von 1 (nullbasiert) dieselbe Dateiposition von 4 ist (wobei Bytes aus 8 Bits bestehen) – bestsss

+2

im Allgemeinen gibt es kein plattformübergreifendes Konzept von endianess: Wenn Sie einen "double" -Wert verwenden, um die Endianz zu überprüfen, erhalten Sie die Endiane dieses Typs und nichts mehr; Außerdem verstehe ich Ihren Algorithmus für die Erkennung von Endianität nicht, indem er auf Platte schreibt: Standard-io ist byte-orientiert, und Sie werden keine weiteren Informationen daraus erhalten, als wenn ich in char * ' – Christoph

+0

konvertieren würde um zu sehen, wie TCP/IP-Sockets auf einer solchen 32-Bit-Plattform implementiert würden. –

0

Struktur bitfields sollte noch richtig auf jeder Plattform arbeiten, auch diese ein:

union { 
    int i; 
    struct { 
     int b1 : 8; 
     int b2 : 8; 
     int b3 : 8; 
     int b4 : 8; 
    } s; 
} u; 

u.i = 1; 
if (u.s.b1 != 0) 
    .... 
+2

Funktioniert nicht, weil Compiler (zumindest die, mit denen ich gearbeitet habe) die Bytes für die Bitfelder in Speicherreihenfolge verwenden. Somit wird "u.b1 == 1" sowohl mit der Little-Endian- als auch der Big-Endian-Plattform wahr sein. (Diese Lösung funktioniert nicht einmal mit Bitfeldern von 1 Bit.) –

+0

Die Reihenfolge der Bits ist maschinenabhängig IIRC, also bin ich mir nicht sicher, ob das funktionieren würde – Hasturkun

-1

Wenn Ihr Code darauf angewiesen ist zu wissen, ob Architektur BE oder LE ist, dann sollte Ihr Code eine Sicherheit haben und nicht für unbekannte Plattform kompilieren. Einige #if ! defined(ARCH_IS_LE) && ! defined(ARCH_IS_BE) \ #error unknown architecture sollten tun.

0

Die Frage bietet nicht genug Informationen, aber w/was es bietet, würde ich sagen: nicht möglich.

0

htonl sollte funktionieren:

if(htonl(1)==1) { 
    /* network order (big-endian) */ 
} else { 
    /* little-endian */ 
} 

(ich keinen Grund sieht, kann nicht htonl und Freunde in der üblichen Weise zu implementieren, auch für diese lästigen hypothetischen System - obwohl ich nicht sicher bin, wie viel helfen sie würden sich in der Praxis erweisen.)

0

Sie könnten die betreffende Variable verschieben und sehen, von welchem ​​Ende die 1 verschiebt.