Kapitel 03: Fundamente: Variablen & Typen (Hardware- & Systemsicht)
Dieses Kapitel analysiert die Repräsentation von primitiven Typen im Speicher, das Phänomen des Speicher-Paddings, Alignment-Regeln der CPU und die mathematische Repräsentation von Überläufen im Statusregister.
1. Lernziele
Sie werden in diesem Abschnitt:
- Die Speichergröße und das Alignment von primitiven Typen auf Systemebene berechnen.
- Das Konzept des Speicher-Paddings (Füllbytes) zur Gewährleistung effizienter Speicherzugriffe verstehen.
- Die Repräsentation des
char-Typs als UTF-32-Scalar auf Bitebene analysieren. - Die Behandlung von Überläufen über die Statusflags des Prozessors nachvollziehen.
2. Speicher-Alignment und Padding auf Hardware-Ebene
Moderne CPUs greifen auf das RAM nicht byte-weise, sondern in Worten (Wörtern) von meist 4 oder 8 Bytes (z. B. 64-Bit-Worte) zu. Um die Leseleistung zu maximieren, müssen Daten im Speicher an Adressen liegen, die ein Vielfaches ihrer eigenen Größe sind (Alignment).
Wenn wir verschiedene Typen mischen, fügt der Compiler unsichtbare Füllbytes (Padding) ein:
Typ-Layout im Speicher:
let a: u8 (1 Byte) --> [ a ]
let b: u32 (4 Bytes) --> [ P ] [ P ] [ P ] [ b ] [ b ] [ b ] [ b ]
(P = Padding-Bytes für 4-Byte-Alignment von b)
Würde Rust das Padding nicht einfügen, müsste die CPU für den Zugriff auf b zwei Speicherzugriffe durchführen und die Bits verschieben, was die Leistung massiv beeinträchtigen würde.
3. Physikalische Repräsentation von char und String
Ein char in Rust ist nicht mit einem char in C/C++ (welches 1 Byte groß ist und der ASCII-Tabelle entspricht) zu vergleichen.
char(UTF-32): Jedescharbelegt exakt 4 Bytes im Speicher. Dies entspricht einem Unicode-Codepoint. Der Wert wird intern als 32-Bit-Ganzzahl (UTF-32) repräsentiert, was den direkten Zugriff auf Zeichen wie Emojis (‘🦀’) auf CPU-Ebene ohne Dekodierungsaufwand ermöglicht.String/&str(UTF-8): Textketten werden in Rust als UTF-8-kodierte Byte-Arrays gespeichert. Hier belegt ein Zeichen je nach Symbol zwischen 1 und 4 Bytes. Der Buchstabe'a'belegt im String 1 Byte, das Emoji'🦀'jedoch 4 Bytes.
4. Integer-Überlauf auf CPU-Ebene
Auf Prozessorebene wird jede arithmetische Operation von der ALU (Arithmetic Logic Unit) durchgeführt. Die ALU setzt bei Berechnungen Flags im Statusregister (z. B. FLAGS bei x86):
- Overflow Flag (OF): Wird gesetzt, wenn das Ergebnis einer vorzeichenbehafteten Operation das Vorzeichenbit verfälscht (Überlauf bei
i32). - Carry Flag (CF): Wird gesetzt, wenn eine vorzeichenlose Operation einen Übertrag erfordert (Überlauf bei
u32).
Wie Rust Flags nutzt
- Debug-Modus: Der Compiler generiert nach arithmetischen Operationen Abfragen dieser Flags (z. B.
intooder bedingte Sprünge wiejofür Jump on Overflow). Wird das Flag gesetzt, löst das Programm einen Systemabbruch (Panic) aus. - Release-Modus: Der Compiler ignoriert diese Flags bei Standardoperationen. Die CPU verwirft das überlaufende Bit hardwareseitig (klassisches Zweierkomplement-Wrapping), was maximale Geschwindigkeit garantiert.
5. Key Takeaways (Systemebene)
- Alignment erzwingt, dass Daten an Speicheradressen liegen, die ihrer Größe entsprechen, was zu Padding-Bytes führen kann.
- Ein
charist ein 4-Byte-UTF-32-Wert; Strings hingegen nutzen die kompaktere UTF-8-Codierung auf Heap-Ebene. - Überläufe werden direkt von CPU-Hardwareflags (
OF,CF) gemeldet, was Rust im Debug-Modus zur Absicherung abfängt.