3 Punkte von GN⁺ 2025-05-31 | Noch keine Kommentare. | Auf WhatsApp teilen
  • C3 basiert auf der Sprache C und bietet fortgeschrittene Funktionen wie Module, Operator Overloading, Generics und Compile-Time-Ausführung
  • Die vertraute C-Syntax bleibt erhalten, ergänzt um Syntax zur Steigerung von Produktivität und Stabilität wie Fehlerbehandlung, defer und foreach
  • Durch die Einführung von deklarativen Contracts sowie optionalen Typen und einer Fehlerbehandlungsweise werden Sicherheit und Klarheit verbessert
  • Unterstützt werden eine Standardbibliothek, integriertes Build-System und praktische Entwicklungsumgebung mit Features wie temporärer Speicherallokation
  • Bei Build, Projekterstellung und Codestruktur gibt es Ähnlichkeiten zur Sprache Zig, wodurch sich neue Experimente im Sprachdesign erkennen lassen

Überblick und Merkmale von C3

Was ist C3?

  • C3 ist eine auf der bestehenden Sprache C aufbauende Sprache, die die vertraute Syntax beibehält und zugleich Funktionen bietet, die in C schwer umzusetzen sind, etwa Modulsystem, Operator Overloading, Generics, Compile-Time-Ausführung, Fehlerbehandlung, defer, Value Methods, schrittweise Contracts, Slices, foreach und Unterstützung für dynamische Typen
  • Eine Modulstruktur mit Namespaces verhindert Namenskonflikte (imperative Namespaces wie abc::Context)
  • Das Hauptziel ist es, Produktivität zu steigern und moderne Systemprogrammierfunktionen sicher bereitzustellen

Sprachmerkmale

Hello-World-Beispiel

  • Syntaktisch C sehr ähnlich
  • Bei Funktionsdeklarationen muss das Schlüsselwort fn explizit verwendet werden
  • Standardbibliotheksfunktionen wie Ein-/Ausgabe sind leistungsfähig, und auch verschiedene Typen lassen sich direkt ausgeben

foreach-Schleife

  • Anders als C wird die foreach-Syntax standardmäßig unterstützt
  • Für Iteration per Referenz wird vor dem Variablennamen & geschrieben (fortgeschrittene Funktion)
  • break und continue werden unterstützt, ähnlich wie foreach in anderen Sprachen

while-Schleife

  • Vor C99 konnten Deklarationen nicht innerhalb der while-Bedingung verwendet werden, in C3 ist eine interne Deklaration möglich

enum und switch-Anweisung

  • In switch-Anweisungen wird implizites break unterstützt (gemischte implizite/explizite breaks sind Geschmackssache)
  • Mit dem Schlüsselwort nextcase wird ein klarer Fallwechsel unterstützt (praktisch für die einfache Implementierung von Jump Tables)
  • Dadurch lässt sich der in Sprachen wie Zig oder C oft komplexe switch-case-Ablauf kompakter steuern

Schlüsselwort defer

  • Beim Verlassen eines Scopes werden mit defer reservierte Anweisungen in umgekehrter Reihenfolge ausgeführt, was sichere Ressourcenbereinigung gewährleistet
  • Nutzung von defer in Kombination mit catch und try (Steuerung des Fehlerbehandlungsflusses)

struct und union

  • Innerhalb von struct sind benannte oder anonyme Sub-structs/unions erlaubt, wodurch sich tagged-union-Muster leicht entwerfen lassen
  • Die Unterscheidung zwischen Anonymität (doppelte gleichnamige Felder) und Namenskonflikten ist streng definiert

Fehlerbehandlung

  • Mit dem Symbol ? werden optionale Typen unterstützt; Fehler und Werteoptionen werden für bessere Nutzbarkeit zusammengeführt
  • Mit dem Schlüsselwort catch kann auf leere Zustände (ohne Optional) bzw. Fehler verzweigt werden
  • Im Gegensatz zu Rust oder Zig ist die Trennung zwischen Fehlern und optionalen Werten schwächer (Vorteil: einfach, Nachteil: geringere Klarheit der Intention)
  • Mit dem Operator ! (rethrow) können Ausnahmen weitergereicht werden

Contracts

  • Vor- und Nachbedingungen von Funktionen (Require/Ensure) werden zwischen <* .. *> geschrieben (Bedingungen werden beim Kompilieren geprüft)
  • Unterstützt sogar Fold-Analyse zur Compile-Time (statische Analyse ist noch nicht implementiert)

struct-Methoden

  • Mit Typangabe plus Punktnotation (Foo.next) werden zugeordnete Methoden aufgebaut; es gibt einen Namespace (auch für Primitive)
  • Methoden sind für alle Typen erlaubt, darunter struct, union und enum

Makros

  • Makros auf Basis von Compile-Time-Evaluierung (Schlüsselwort macro)
  • Mit $ für Compile-Time-Parameter, mit # für die Übergabe vor der Auswertung
  • C-Stil (minimiert verflochtene Makroprobleme, betont AST-Stabilität, Prüfungen mit @-Präfix usw.)
  • Typ-Reflection und Compile-Time-Ausführung werden über Makros verarbeitet

Type Properties

  • alignof, kindof, extnameof, sizeof, typeid, methodsof, has_tagof, tagof, is_eq, is_ordered, is_substruct usw.
  • Geeignet für Metaprogrammierung und Reflection

Base64-/Hex-Literale

  • Byte-Sequenzen lassen sich direkt in der Form b64"..." und x"..." deklarieren
  • Können durch das eingebaute Makro $embed ersetzt werden (in der Praxis aber selten genutzt)

Primitive Typen

  • Verschiedene Basistypen wie int, uint, char (immer unsigned), bool, float, int128/uint128
  • Zusätzliche Pointer-/Größentypen wie iptr, uptr, isz, usz (etwas weniger intuitiv)
  • Anders als in C ist die Bitgröße garantiert

Sonstiges

  • Breiter Funktionsumfang mit Operator Overloading, Struct-Subtyping, Generics, Runtime Dispatch, Typ any und Bitfeld-Structs (bitstructs)

Praxisteil: Erfahrungen mit C3

C3 installieren

  • Unterstützt werden sowohl Prebuilt-Binaries von der offiziellen Website als auch das direkte Bauen aus dem Quellcode
  • LLVM und LLD müssen installiert sein (bei Link-Problemen können die CMake-Flags -DLLVM_DIR und -DLLD_DIR verwendet werden)
  • Da in einigen Distributionen LLD-Bibliotheken fehlen, wird empfohlen, die Binaries direkt herunterzuladen
  • Der C3-Compiler benötigt die Abhängigkeit libtinfo

Projekt erstellen

  • Mit dem Befehl c3c init wird eine Standard-Ordnerstruktur erzeugt (LICENSE/README.md/project.json/src usw.)
  • Grundlegende Projektkonfiguration für Build, Build-Targets und Source-Setup (ähnlich wie bei Zig oder Cargo)
  • Die Standarddatei main.c3 ist sehr knapp gehalten (Meinung: gut für neue Nutzer)

Einen Rechner bauen

Design und Ziel

  • Zur Übung verschiedener Sprachmerkmale von C3 wie Funktionen, Ein-/Ausgabe, Speicherverwaltung und Schleifen wird ein Recursive-Descent-Parser und die Kernlogik eines Rechners implementiert
  • Ziel ist es, Stärken und Unbequemlichkeiten der Syntax, die Intuitivität und die Praxistauglichkeit für produktive Entwicklung direkt zu erfassen

Eingabeverarbeitung

  • Mit @pool wird ein temporärer Allokator (tmem) verwendet; beim Verlassen des Scopes wird Speicher automatisch freigegeben (Arena Allocator)
  • Unterstützt werden die Standardarten der Speicherverwaltung tmem (temporär) und mem (allgemein), einschließlich des Musters, Allokatoren auf Funktionsebene zu übergeben (Mischung aus Vorteilen von Zig und C)
  • In der main-Funktion muss ein Rückgabewert immer explizit angegeben werden (vom Compiler erzwungen)
  • Funktionen, deren Rückgabewert ignoriert werden darf, werden mit dem Attribut @maydiscard markiert (verhindert böswilliges Ignorieren)

Implementierung des Tokenizers

  • Zerlegt Benutzereingaben in eine Token-Liste
  • Nutzt verschiedene Kontrollstrukturen wie List aus der C3-Standardbibliothek, foreach-Syntax sowie switch-case (nextcase, Kombination aus implizitem/explizitem break)
  • Bei der Slice-Syntax (beide Endindizes inklusive) und Slices der Länge 0 gibt es Verwirrung; dafür existiert eine separate Syntax zur Längenangabe
  • Die Transparenz und Flexibilität der Speicherverwaltung, etwa bei gemischter Nutzung temporärer/allgemeiner Allokatoren, sind stark und anderen Sprachen wie Rust überlegen

Implementierung des Parsers

  • Erfahrungsbericht zum direkten Schreiben eines Parsers (ausgelassen)

Fazit und Gesamteindruck

  • C3 strebt den Schnittpunkt traditioneller Systemsprachen und modernen Designs an
  • Die Sprache wurde unter Studium von Zig, Rust und C entworfen, mit dem Ziel, Leistung und Code-Stabilität zu vereinen
  • Besonders hervorstechend sind Modularität, sichere Behandlung von Speicher/Fehlern/Contracts, starke Metaprogrammierung und ein intuitives Build-System
  • Die Lernkurve ist für Entwickler mit C-Erfahrung schrittweise gut zugänglich
  • Die noch unreife Ökosystem-Unterstützung wie Sprachserver und IDE sowie manche Syntaxentscheidungen mit geteilten Meinungen brauchen Verbesserung
  • Für professionelle Low-Level- und Systementwicklung ist C3 als Alternative der nächsten Generation bemerkenswert

Noch keine Kommentare.

Noch keine Kommentare.