Endianness

Computer adressieren heutzutage Byteweise. Mit einem Byte kann man Werte zwischen 0 und 256 darstellen, so wie es im binären Zahlensystem beschrieben ist. Dort wird genau wie im uns vertrauten Dezimalzahlensystem (10 Ziffern pro Stelle) die höherwertigen Stellen links und die niederwertigen Stellen rechts geschrieben.

Als Beispiel:

12

Die Ziffer 1 bedeutet, dass der Wert Zehn genau einmal in die Summe eingeht. Die Ziffer 1 ist in ihrer Bedeutung also höherwertig im Vergleich zur Ziffer 2, die bedeutet, dass der Wert 1 zweimal in die Summe eingeht. Addiert man die Werte, so erhält man den Wert der Zahl: Zwölf. Jede Stelle weiter links beschreibt einen zehnfachen Wert zur Stelle weiter rechts.

Genauso ist es im Binär-Zahlensystem (zwei Ziffern):

10

Die 1 ist höherwertig, sie steht für den Wert 2, der einmal in die Summe eingeht. Die 0 steht für den Wert 1, der nullmal in die Summe eingeht: Die binäre Zahl 10 hat also den Wert Zwei.

Mit einem Byte können wir 8 Bits darstellen, also die Werte 0 bis 255 in dezimaler Schreibweise. Wenn wir mehr Stellen benötigen, weil wir zum Beispiel die Zahl 256 speichern wollen, dann benötigen wir 9 Bits, also mehr als ein Byte.

1_00000000  ( = dezimal 256)

Stellen wir uns Bytes als Ziffern vor, die von 0 bis 255 gehen, dann ist der Wert Zweihundertsechsundfünfzig in diesem Zahlsystem die Zahl

10 = 1 * Zweihundertsechsundfünfzig + Null

Diese Zahl benötigt also zwei Ziffern. Da ein Computer immer byteweise adressiert benötigen wir zwei Bytes, die ich hier mit einem Unterstrich optisch voneinander trenne:

00000001_00000000  (=dezimal 256 für 16 Bit, Motorola-Format)

Das linke Byte hat nun den wert 1, das rechte den Wert 0. Da sie direkt nebeneinander liegen kann man sie als 16-Bitzahl mit dem Wert 256 interpretieren.

Und genauso wird das auch von beispielsweise Motorola-Prozessoren gehandhabt. Ein x86-kompatibler Prozessor (zum Beispiel: Intel oder AMD) sieht die Sache aber ganz anders. Hier wird die Bytereihenfolge vertauscht:

00000000_00000001  (=dezimal 256 für 16 Bit Intel-Format)

Big Endian

Als BigEndian bezeichnet man die Zahlen die im Speicher mit dem „Großen Ende“ beginnen. Das erste Byte im Speicher ist also das höherwertige Byte, wie es bei Motorola üblich ist. Diese Zahlen lassen sich entsprechend leichter lesen, die Zahl wird immer detaillierter, wie beispielsweise die Uhrzeit (12 Uhr, 34 Minuten, 56 Sekunden) oder ein Verzeichnispfad ( /home/user/documents/ ).

Little Endian

LittleEndian bezeichnet entsprechend die Bytereihenfolge, bei der das „Kleine Ende“ vorne im Speicher liegt. Es wird also das niederwertige Byte zuerst im Speicher abgelegt, wie es bei Intel-Prozessoren üblich ist. Diese Zahlen sind für den Entwickler schwieriger zu lesen. Man stelle sich vor, dass man im Dezimalsystem 4 Stellen anordnet und dann die niederen 4 Stellen zuerst schreibt. Lesen wir dann, dass ein Haus 123456 Euro kostet, dann wäre bei dieser Gruppierung (4 Stellen) in LittleEndian-Anordnung der Wert 34560012 Euro. Am Wert ändert sich nichts, lediglich die Schreibweise ist eine andere. Dies ist für uns allerdings sehr ungewohnt zu lesen.

Bei größeren Datentypen, zum Beispiel 32-Bit, ist die Reihenfolge aller Bytes umgedreht. Das niederwertigste Byte zuerst, gefolgt vom zweiniedrigsten, gefolgt vom zweitwertigen und anschließend vom höchstwertigen Byte.

Wozu ist LittleEndian dann gut?

Computer rechnen häufig mit großen Zahlen, sind dann aber doch nur an einem Detail interessiert. So kann es beispielsweise passieren, dass man auf eine 32-Bit-Variable zugreift. In normaler Reihenfolge (BigEndian: ABCD, A steht für das höchstwertige Byte). Hat man nun die Adresse der Zahl, sagen wir 1000, so liegt das höchstwertige Byte A auf Adresse 1000, B auf 1001, C auf 1002 und D auf Adresse 1003. Braucht man nun aber ausschließlich den Wert vom darin enthaltenen 8 Bit-Wert, also D, so muss man den 32-Bit Wert komplett einlesen und anschließend im Prozessor den Bereich von A, B und C auf Null setzen. Eigentlich hätten wir A, B und C damit gar nicht einlesen müssen. Alte Computer hatten weiterhin oftmals nur 16 oder 24 Bit breite Leitungen zum Arbeitsspeicher, für eine 32-Bit-Zahl mussten sie also zweimal den Speicher auslesen. Das kostet Zeit und das anschließende Löschen von A, B und C kostet ebenfalls Zeit. Nun weiß man, dass D 3 Byte hinter der bekannten Adresse liegt. Also wird auf die Adresse 1000 anschließend 3 addiert und nur ein Byte aus dem Speicher gelesen. Mit dieser Operation müssen A, B und C anschließend nicht mehr gelöscht werden.

Mit LittleEndian liegt das Byte jedoch direkt an Adresse 1000. Wenn wir die Adresse der 32-Bit-Zahl haben, haben wir gleichzeitig auch die Adresse der 8 Bit-Zahl an dieser Stelle. Und genauso gilt das für die 16-Bit-Zahl. Wenn wir also nur den niederwertigen Teil einer Zahl auslesen wollen, spart das Little-Endian-Format Rechenleistung.

Wer benutzt was?

Nun sind klassische Unix-Systeme vor allem auf BigEndian-Systemen entwickelt worden, während Windows auf LittleEndian-Systemen beheimatet ist. Aber diese Welten kollidieren zum Beispiel über das Internet miteinander. Die Internet-Protokolle kommen aus dem Unix-Bereich. Entsprechend sind Zahlen, die zu den Internetprotokollen (z.B. TCP/IP) gehören im BigEndian-Format kodiert und damit Windows im Internet mitmachen darf, muss es die Protokolle entsprechend mit BigEndian-Zahlen verarbeiten. Linux läuft häufig auf Intel-Hardware, also ebenfalls mit Hardware, die Little-Endian verwendet.

Entsprechend muss man beim Austausch von Daten aufpassen, wie das Datenformat geschrieben wurde.

Zahlen

Einige Datenformate, wie beispielsweise das Bildformat TIFF, bieten beide Varianten an. Hier ist nur der Header festgelegt. Darin schreibt das Programm, dassdas Bild schreibt eine festgelegte Zahl. Liest man die Zahl nun nach seinen Wünschen ein, stellt man fest, ob die Zahl im eigenen Format geschrieben wurde oder ob man konvertieren muss.

Strings

Für Motorola-CPUs wurden gelegentlich kurze Strings, zum Beispiel für IDs mit 32-Bit-Integern versehen:

int id = 'A' << 24 | 'B' << 16 | 'C' << 8 | 'D';

Hier landet das A auf dem höhstwertigen Byte, das 'D' auf dem niederwertigsten.

Schrieb man nun die 4 Byte ab der Adresse der Variablen (&id) in eine Datei, erhielt man unter Motorola-CPUs den String „ABCD“. Macht man dies mit einem Intel-Rechner, so erhält man „DCBA“. Auch hier gilt es also darauf zu achten, die Reihenfolge entsprechend für die jeweilige CPU zu konvertieren.

Fragen?

Einfach im Forum melden.