====== Lyx – Low-Level: Speicherzugriff & Pragmas ====== Systemprogrammierung – Treiber, Kernel-Module, Echtzeit-Regler, Hardware-Abstraktionen – erfordert direkten Zugriff auf Speicheradressen. Lyx löst das **ohne Zeigertypen**: Eine Adresse ist ein gewöhnlicher ''int64'', gelesen und geschrieben wird mit den eingebauten Primitiven ''peek''/''poke''. > **Ein Zeigermodell gibt es in Lyx nicht.** Diese Seite beschrieb früher eine Pascal-artige Syntax (''%%^T%%'' als Typ, ''%%^x%%'' für die Adresse, ''%%p^%%'' zum Dereferenzieren) sowie mehrere Pragmas. Keines dieser Konstrukte ist umgesetzt: > > ^ Konstrukt ^ Verhalten ^ > | ''%%var p: ^int64%%'' | ''unknown type in var decl'''' ''%%'^'%%'' | > | ''%%^x%%'' (Adresse von) | ''expected expression'' | > | ''%%p^%%'' (Dereferenz) | Parse-Fehler | > | ''unsafe { … }'' | ''undefined symbol '\''unsafe'\'''' | > | ''@inline'', ''@no_opt'', ''@section'', ''@parallel'' | ''unbekanntes Attribut'' | > > ''%%^%%'' ist in Lyx ausschließlich der **XOR-Operator**: ''6 %%^%% 3'' ergibt ''5''. > > Die Grammatik führt in ''PrimaryType'' folgerichtig keinen Zeigertyp. Was stattdessen gilt, steht unten und ausführlich unter [[lyx_-_programmiersprache:sprache:rohspeicher|Rohspeicher]]. → [[lyx_-_programmiersprache:sprache:rohspeicher|Rohspeicher: alloc, peek & poke]] · [[lyx_-_programmiersprache:sprache:memory-management|Memory Management]] · [[lyx_-_programmiersprache:sprache:attributes-pragmas|Attribute & Pragmas]] ---- ===== 1. Adressen sind int64 ===== Eine Adresse wird wie eine Zahl behandelt. ''alloc'' liefert sie, ''peek''/''poke'' greifen darauf zu, ''free'' gibt frei — Größe ist dabei Pflicht, weil Lyx keine versteckten Metadaten führt. import std.io; import std.alloc; fn main(): int64 { var zelle: int64 := alloc(8); // 8 Bytes, Adresse als int64 if (zelle == 0) { return 1; } // 0 = kein Speicher poke64(zelle, 42); // schreiben PrintLn(IntToStr(peek64(zelle))); // lesen -> 42 free(zelle, 8); return 0; } ^ Primitiv ^ Breite ^ Zweck ^ | ''peek8'' / ''poke8'' | 1 Byte | Protokoll-Bytes, Zeichen | | ''peek16'' / ''poke16'' | 2 Byte | kompakte Felder | | ''peek32'' / ''poke32'' | 4 Byte | Hardware-Register, IPv4 | | ''peek64'' / ''poke64'' | 8 Byte | Standardfall, Adressen | | ''peekf64'' / ''pokef64'' | 8 Byte | Gleitkomma | Alle sind **eingebaut** — kein Import nötig. ''alloc'' und ''free'' kommen aus ''std.alloc''. ==== Einen Wert zurückgeben ==== Da es keinen Adressoperator gibt, lässt sich die Adresse einer lokalen Variablen nicht nehmen. Ein Ausgabeparameter wird deshalb als **Zelle** übergeben: import std.io; import std.alloc; fn TeileMit(a: int64, b: int64, restZelle: int64): int64 { poke64(restZelle, a % b); return a / b; } fn main(): int64 { var rest: int64 := alloc(8); var quotient: int64 := TeileMit(17, 5, rest); PrintLn(IntToStr(quotient)); // 3 PrintLn(IntToStr(peek64(rest))); // 2 free(rest, 8); return 0; } ---- ===== 2. Structs über Byte-Offsets ===== Ein Struct auf dem Heap wird über seine Feld-Offsets angesprochen. Die [[lyx_-_programmiersprache:units|Standardbibliothek]] arbeitet durchgehend so — ''A.feld'' bezeichnet in Lyx den **Byte-Offset** des Feldes: import std.io; import std.alloc; type Punkt = struct { x: int64; y: int64; }; fn main(): int64 { var p: int64 := alloc(16); poke64(p + Punkt.x, 3); poke64(p + Punkt.y, 4); PrintLn(IntToStr(peek64(p + Punkt.x))); // 3 PrintLn(IntToStr(peek64(p + Punkt.y))); // 4 free(p, 16); return 0; } ''sizeof(ausdruck)'' liefert die Breite eines Werts in Bytes — es nimmt einen **Ausdruck**, keinen Typnamen: ''sizeof(1)'' ergibt ''8''. Für Strukturen auf dem Stack ist der gewöhnliche Feldzugriff der richtige Weg; Rohspeicher braucht es nur, wo die Lebensdauer über den Aufruf hinausreicht oder die Größe erst zur Laufzeit feststeht. ---- ===== 3. @volatile – Memory-Mapped I/O ===== Auf Mikrocontrollern sind Hardware-Register in den Adressraum eingeblendet. ''@volatile'' verhindert, dass der Compiler wiederholte Zugriffe auf dieselbe Adresse wegoptimiert. @volatile var GPIO_OUT: int64 := 0x3FF44004; Der Zugriff erfolgt über ''poke32''/''peek32'' auf die Adresse: fn LedAn(pin: int64): int64 { poke32(0x3FF44004, 1 << pin); return 0; } ---- ===== 4. packed struct – Layout ohne Füllbytes ===== ''packed struct'' legt die Felder ohne Ausrichtungslücken ab — nötig für Protokollrahmen und Hardware-Strukturen, deren Byte-Anordnung festliegt. type Kopf = packed struct { typ: uint8; laenge: int64; }; ''flat struct'' gibt es ebenfalls; beide sind unter [[lyx_-_programmiersprache:sprache:datentypen|Datentypen]] beschrieben. ---- ===== 5. null ===== ''null'' ist gültig und entspricht der Adresse ''0'' — dem Wert, den ''alloc'' im Fehlerfall liefert: var zelle: int64 := alloc(64); if (zelle == null) { return 1; } // gleichbedeutend mit == 0 ---- ===== 6. Speicherzugriff im Safety-Umfeld ===== ^ Situation ^ Empfehlung ^ | Regelzyklus (DAL-A/B) | Statische Arrays ''[N]T'' und Structs auf dem Stack — keine Allokation | | Puffer bekannter Größe | ''[N]uint8'' statt ''alloc'' | | Hardware-Register | ''@volatile'' plus ''peek32''/''poke32'' | | Dynamische Größe | ''alloc''/''free'' mit gepaarter Freigabe, außerhalb des Regelzyklus | Eine Freigabe gehört in jeden Pfad, der sie erreicht — Lyx hat keine Destruktoren. Details unter [[lyx_-_programmiersprache:sprache:std-fehlerkonventionen|Fehler-Konventionen]] und [[lyx_-_programmiersprache:sprache:memory-management|Memory Management]]. ---- **Weiterführende Seiten:** * [[lyx_-_programmiersprache:sprache:rohspeicher|Rohspeicher — alloc, peek & poke im Detail]] * [[lyx_-_programmiersprache:sprache:memory-management|Memory Management — Lebensdauer und Freigabe]] * [[lyx_-_programmiersprache:sprache:attributes-pragmas|Attribute & Pragmas — vollständige @-Referenz]] * [[lyx_-_programmiersprache:sprache:datentypen|Datentypen — packed/flat struct]] Codebeispiele geprüft: gegen **lyxc 1.2.5C** übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die ''pub fn''-Signaturen in ''aurum/std'' gehalten, 0 Abweichungen).