Grundlagen maschinennaher Informationsdarstellung
Die aktiven Elemente in digitalen Schaltungen (Transistoren in CPUs, Speicher, Controller etc.) können nur in den beiden Zuständen "ein" oder "aus" betrieben werden. Damit ergibt sich in natürlicher Weise eine binäre (zweiwertige) Darstellung der Information. Jede Information muss somit in einer Folge der Zustände ein/aus oder 1/0 ausgedrückt werden.
"Geschriebene" Information wie zum Beispiel dieser Text wird durch eine Folge von Buchstaben, Ziffern und Sonderzeichen ausgedrückt. Man verwendet eine Reihe von Symbolen, um alle diese Buchstaben, Ziffern und Sonderzeichen darstellen und voneinander unterscheiden zu können. Um diese Symbole auch in einem Computer verwenden zu können, benötigt man einen Code, der den Symbolen unterschiedliche Zahlenwerte zuordnet. Natürlich gibt es viele verschiedene Möglichkeiten, einen solchen Code zu erstellen. Tatsächlich gibt es auch mehr als einen Code für die Zuordnung von Zeichen zu Zahlenwerten. Einer dieser Codes ist der so genannte ASCII (American Standard Code of Information Interchange)-Code.
Dezimal- und Binärsystem
Die uns geläufigen Dezimalzahlen werden mit Hilfe der zehn Ziffern 0 bis 9 dargestellt. Es stehen also zehn verschiedene Zeichen oder Zustände für die Darstellung zur Verfügung. Dem Computer stehen aber nur zwei Zustände zur Verfügung, nämlich 0 und 1. Um die Zahlendarstellung in einem Computer zu verstehen, müssen wir zunächst analysieren, wie eine Dezimalzahl interpretiert wird.
Unser Zahlensystem wird auch als Stellensystem bezeichnet (etwa im Gegensatz zu den römischen Zahlen), weil jede Stelle einer Dezimalzahl einem bestimmten Wert entspricht. Wenn wir zunächst nur natürliche Zahlen betrachten, dann weist die am weitesten rechts stehende Stelle der Wert eins, die zweite Stelle von rechts den Wert zehn, die dritte Stelle von rechts den Wert hundert usw. auf. Die Anzahl solcher Werte je Stelle wird durch die an der betreffenden Stelle stehende Ziffer angegeben.
Beispiel:
Interpretation der Zahl 4711
1*1 + 1*10 + 7*100 + 4*1000
oder in Potenzen ausgedrückt
1*100 + 1*101 + 7*102 + 4*103
Dieses Schema lässt sich für beliebig große Zahlen erweitern. Die Zahl 10 stellt dabei die Basis des Zahlensystems dar (daher der Begriff Dezimalzahlen); sie stimmt mit der Anzahl unterschiedlicher Ziffern überein. In einem Computer stehen aber nicht zehn, sondern nur zwei solcher Ziffern zur Verfügung. Daher muss die Zehn durch zwei ersetzt werden. Das führt uns zum Dual- oder Binärsystem. Zahlen im Binärsystem werden durch die Ziffern 0 und 1 dargestellt.
Beispiel:
Die binäre Zahl 1001001100111 bedeutet
1*20 + 1*21 + 1*22 + 0*23 + 0*24 + 1*25 + 1*26 + 0*27 + 0*28 + 1*29 + 0*210 + 1*212
Wir erhalten somit zwei verschiedene Darstellungen der Zahl 4711: 4711 im Dezimalsystem und 1001001100111 im Binärsystem. Auch das binäre Schema lässt sich wie die Dezimalzahlen zu beliebig großen Werten fortsetzen. Man erkennt aber sofort einen großen Nachteil des Binärsystems gegenüber dem Dezimalsystem: die Zahlen werden erheblich länger, d.h. man benötigt sehr viel mehr Platz, um sie aufzuschreiben.
In diesem Zusammenhang werden zwei wichtige Begriffe verwendet: Eine binäre Ziffer oder Stelle im Binärsystem heißt Bit. Acht Stellen, d.h. acht binäre Ziffern werden zu einem Byte zusammen gefasst. Mit einem Byte lassen sich insgesamt 28 = 256 verschiedene Zahlen darstellen, und zwar die dezimalen Zahlen 0 bis 255. Man kann natürlich ein Bit aus den acht Bits eines Bytes dazu verwenden, um ein Vorzeichen (+ oder -) zu codieren. Dann können die (dezimalen) Zahlen -128 bis +127 in einem Byte dargestellt werden.
Zwei Bytes werden als Wort (engl. Word), vier Bytes als Langwort (engl. Longword) bezeichnet. Durch die Gruppierung mehrerer Bytes lassen sich auch größere Zahlen darstellen. Mit einem Longword lassen sich beispielsweise die Zahlen von 0 bis 232-1 (=4.294,967.295) darstellen, wenn kein Bit als Vorzeichenbit verwendet wird. Man spricht dann auch von unsigned long integer Zahlen. Mit Vorzeichen (signed long integer) lassen sich die Zahlen von -231 bis +231-1 in einem Langwort darstellen.
Der ASCII-Code
Im ASCII-Code (American Standard Code of Information Interchange) wird jedem der 256 verschiedenen Werte eines Bytes ein Zeichen zugeordnet. Es werden also die 256 "wichtigsten" Zeichen durchnummeriert. Die Zuordnung von Nummern und Zeichen ist im Prinzip völlig willkürlich, so hat es beispielsweise keine tiefere Bedeutung, dass dem Buchstaben A gerade die Zahl 65 zugeordnet wurde.
Eigentlich definiert der ASCII-Code nur 128 Zeichen (das höchstwertige Bit des Bytes ist immer 0). Damit standen nicht genug Codes zur Verfügung, um alle Zeichen der wichtigsten Sprachen zu codieren. Man beschränkte sich auf die Zeichen, die in der Geschäftswelt der USA üblich sind. Somit enthält der ASCII-Code zwar die eckigen und geschwungenen Klammern, nicht aber Umlaute oder Buchstaben, die einen Akzent benötigen.
Spätere Erweiterungen des Codes haben auch das höchstwertige Bit mit einbezogen, wodurch mehr Zeichen zur Verfügung stehen. Leider folgten die verschiedenen Rechnerhersteller bei dieser Erweiterung auf 256 verschiedene Zeichen keiner einheitlichen Vorgabe. So wies der Zeichensatz des PCs unter dem Betriebssystem MS DOS für bestimmte Zeichen andere Codes auf als der Zeichensatz des Apple Macintosh. UNIX-Rechner verstanden wiederum lange Zeit überhaupt nur die 128 Zeichen des ursprünglichen ASCII-Codes. Erst im Lauf der Neunziger Jahre des 20. Jahrhunderts einigte man sich schließlich auf den so genannten ANSI-Code, der unter anderem von Windows verwendet wird.
Zu bemerken ist auch, dass nicht alle Zeichen des ASCII- bzw. des ANSI-Codes druckbare Zeichen sind. Eine Reihe von Zeichen (z.B. die Zeichen mit den Zahlenwerten von 0 bis 31) stellen Steuercodes dar. Sie dienen dazu, dem Empfänger Mitteilungen über die gesendeten Daten zu machen. Man muss in diesem Zusammenhang bedenken, dass die Zeichencodes nicht nur statisch in einer Datei gespeichert werden können, um einen geschriebenen Text darzustellen; mit Hilfe dieser Codes können auch Informationen Zeichen für Zeichen (also Byte für Byte) über eine Datenleitung übertragen werden. Zur sicheren Übertragung der Zeichen benötigt man auch Steuerinformationen (z.B. für Anfang und Ende der Datenübertragung oder ob der Empfänger noch bereit ist, Daten in Empfang zu nehmen). (Diese Steuerzeichen haben allerdings nichts mit den Modem-Steuersignalen zu tun.)
Der ASCII- (ANSI-)Code eignet sich also gut zur Darstellung von Texten. Bildet man eine Kette aus mehreren aufeinanderfolgenden ASCII-Codes also eine Kette aufeinanderfolgender Zeichen , erhält man eine Zeichenkette oder einen String. Da Strings unterschiedlich lang sein können, muss in irgend einer Form auch die Länge der Zeichenkette angegeben werden. Dafür stehen mehrere Methoden zur Verfügung:
Neben dem ASCII-Code gibt es auch andere Codes. Von Bedeutung ist heute noch der EBCDIC-Code (Extended Binary Coded Decimal Interchange Code), der insbesondere in Großrechnern verwendet wird. Es handelt sich dabei um einen 8-Bit-Code, der immer schon auch Zeichen enthielt, die nur außerhalb der USA Verwendung finden.
Zweierkomplement, negative ganze Zahlen
Für die Darstellung von negativen Zahlen hat sich in der Computertechnik aus praktischen Gründen die so genannte Zweierkomplementdarstellung durchgesetzt: Eine negative ganze Zahl wird dargestellt, indem bei der entsprechenden positiven ganzen Zahl alle Nullen durch Einsen und alle Einsen durch Nullen ersetzt werden und zu dem so gewonnenen Ergebnis 1 addiert wird.
Beispiel (die Abstände nach
jeweils vier Bits dienen lediglich der Lesbarkeit):
| positive ganze Zahl 256: | 0000 0001 0000 0000 |
| negative ganze Zahl -256: | |
| komplementieren 1 addieren Ergebnis |
1111 1110 1111 1111 |
Ist bei vorzeichenbehafteten (signed integer) Ganzzahlen das höchstwertige (d.h. das am weitesten links stehende) Bit gleich 1, handelt es sich um eine negative Zahl. Man beachte, dass die Interpretation eines Bitmusters verschiedene Ergebnisse liefert, je nachdem, ob man das Bitmuster als unsigned integer oder als signed integer betrachtet:
Beispiele:
(a) Wir betrachten die Binärzahl 1111 1111 0000 0000 von
oben:
| Interpretation als vorzeichenlose ganze Zahl (unsigned integer): | 1111 1111 0000 0000: 0*20 + 0*21 + 0*22 + 0*23 + 0*24 + 0*25 + 0*26 + 0*27 + 1*28 + 1*29 + 1*210 + 1*211 + 1*212 + 1*213 + 1*214 + 1*215 = 65280 |
| Interpretation als vorzeichenbehaftete ganze Zahl (signed integer): Das höchstwertige Bit ist 1, daher ist die Zahl negativ; Umkehrung der Prozedur von oben: | 1111 1111 0000 0000: |
| eins subtrahieren komplementieren Ergebnis |
1111 1111 0000 0000 |
| Das Ergebnis ist also als -256 zu interpretieren. |
(b) Wenn eine vorzeichenbehaftete Binärzahl aus lauter Einsen besteht, lautet das Ergebnis -1. Zum Nachweis nehmen wir ein Byte an, dessen acht Bits alle auf 1 gesetzt sind. Das Byte ist als vorzeichenbehaftete ganze Zahl zu interpretieren:
| Gegeben ist: eins subtrahieren liefert komplementieren: |
1111 1111 1111 1110 0000 0001 |
Die Zweierkomplementdarstellung wird für alle ganzen Zahlen (Bytes, Words, Longwords, ) in gleicher Weise angewandt.
Hexadezimalzahlen
Die Darstellung von Zahlen durch eine Folge von Nullen und Einsen ist sehr umständlich. Bei längeren Bitfolgen verliert man schnell den Überblick. Es liegt daher nahe, mehrere Bits zu einer einzigen Zahl zusammenzufassen. Meist sind dies vier Bits, in früheren Tagen der EDV waren es manchmal auch nur drei Bits. Wenn vier Bits zu einer einzigen Zahl zusammengefasst werden, gelangt man zu einem Zahlensystem mit der Basis 16 (=24). (Bei drei Bits erhält man die Basis 8 = 23.)
Die Basis 16 ist Grundlage des Hexadezimalsystems. In diesem System existieren Ziffern mit den dezimalen Werten von 0 bis 15. Für die Hexadezimalziffern "10" bis "15" müssen neue Symbole gefunden werden. Es werden dafür die Buchstaben A bis F (bzw. a bis f) verwendet. Um eine Hexadezimalzahl zu kennzeichnen, wird ihr oft ein h oder H nachgestellt, damit man sie nicht mit einer Dezimalzahl verwechselt. Eine andere Kennzeichnung von Hexadezimalzahlen ist ein vorangestelltes "0x" (z.B. in der Programmiersprache C).
Mit Hilfe von Hexadezimalzahlen erhält man eine wesentlich kompaktere Schreibweise, wobei die Zahlen überdies rasch in eine Binärzahl übergeführt werden können. Hexadezimalzahlen haben wie Binärzahlen kein Vorzeichen, erst die Interpretation entscheidet, ob sie positiv oder negativ sind.
Beispiele:
| vorzeichenlose dezimale Zahl (ganze Zahl): | 65535 |
| Binärzahl: | 1111 1111 1111 1111 (die Abstände nach jeweils vier Bits dienen lediglich der Lesbarkeit) |
| Hexadezimalzahl: | FFFFh |
| Hexadezimalzahl: | 9BE7h |
| Binärzahl: | 1001 1011 1110 0111 |
| Dezimalzahl: | 9*16³ + 11*16² + 14*16 + 7*1 = 39911 (interpretiert als vorzeichenlose Ganzzahl; eine Interpretation als vorzeichenbehaftete Ganzzahl würde übrigens -25625 ergeben.) |
Little-Endian-Format
Die Prozessoren von Intel verwendet das so genannte Little-Endian-Format. Das bedeutet, dass ein Wort oder Langwort stets mit dem niederwertigen Byte (least significant byte) beginnt und mit dem höchstwertigen (most significant byte) endet. Das bedeutet, dass ein höherwertigeres Byte einer Größe, die aus mehr als einem Byte besteht, an einer höheren Adresse gespeichert wird als ein niederwertigeres Byte.
Wenn man ein Wort oder Langwort aufschreibt, setzt man das höchstwertige Byte an die am weitesten links stehende Position und das niederwertigste Byte an die am weitesten rechts stehende Stelle. Wenn man Speicheradressen niederschreibt, steigen sie aber üblicherweise von links nach rechts an. Daher scheinen die Speicherinhalte von Little-Endian-Prozessoren im Vergleich zu ihrer "erwarteten" Reihenfolge in Worten oder Langworten byteweise vertauscht zu sein. Das betrifft auch die Inhalte von Dateien, weil sie oft ein genaues Abbild von Speicherinhalten enthalten.
Ein Wort mit dem (hexadezimalen) Wert 12DEh wird also im Memory als DE12h aufscheinen, ein Langwort mit dem Inhalt 12345678h wird abgelegt als 78563412h. Das ist bei der Untersuchung von Speicherabbildern ("Hex-Dumps") zu berücksichtigen.
Big-Endian-Format
Im Gegensatz dazu beginnt ein Wort oder Langwort im Big-Endian-Format immer mit dem most significant byte. Prozessoren von Motorola verwenden dieses Format.
Wenn binäre Daten zwischen Rechnern unterschiedlicher Architektur ausgetauscht werden sollen (beispielsweise mit Hilfe des Programms FTP), muss der Umstand, dass zusammen gehörige Bytes in unterschiedlicher Reihenfolge gespeichert sein können, berücksichtigt werden. Es gibt dazu eine eigens definierte Network Byte Order. Die Network-Byte-Order stimmt mit dem Big-Endian-Format überein.