Modern C C23 Edition
(gustedt.wordpress.com)- Eine an den neuen C-Standard angepasste überarbeitete Ausgabe von Modern C steht als kostenloser Download bereit, sodass Lern- und Referenzmaterial zur Programmiersprache C nun auf Basis von C23 neu betrachtet werden kann
- Im Mittelpunkt der Überarbeitung steht die Berücksichtigung von C23; der Fokus liegt darauf, den Übergang zum neuen Standard im Einklang mit dem ISO-Veröffentlichungsprozess und dessen Zeitplan zu erleichtern
- Neue Releases der wichtigsten Compiler haben bereits den Großteil der C23-Funktionen implementiert, sodass die Änderungen im Buch über eine experimentelle Vorstellung hinausgehen und an reale Einsatzumgebungen anschließen
- Sprach- und Bibliotheksänderungen wie
_BitInt(N),nullptr,auto,typeofundconstexprwerden breit berücksichtigt und wirken sich auch auf die bisherige Art aus, C-Code zu schreiben - Damit man es auf bestehenden Plattformen direkt ausprobieren kann, wurden ein Anhang für die Migration und temporäre Include-Header ergänzt; Mannings MEAP ist jedoch noch in Arbeit
Kostenlos verfügbare Materialien und Standarddokumente
- Die Modern C C23 Edition kann kostenlos heruntergeladen werden
- Download: https://hal.inria.fr/hal-02383654
- Auf der dedizierten Buchseite finden sich auch zugehörige Materialien
- Buchseite: https://gustedt.gitlabpages.inria.fr/modern-c/
- Dort gibt es auch den Download-Link für die mit dem Buch bereitgestellten Codebeispiele
- Die überarbeitete Ausgabe hat viele Erklärungen angepasst, ihr Hauptzweck ist jedoch, den neuen C-Standard C23 abzubilden
- Unter den öffentlich zugänglichen Dokumenten kommt N3220 PDF den Inhalten des neuen Standards am nächsten
- Neue Releases der wichtigsten Compiler implementieren bereits den Großteil der neuen Funktionen, die C23 mitbringt
Sprachänderungen in C23 und Unterstützung beim Umstieg
- Änderungen rund um Integer machen einen großen Teil aus
- Neuer bitgenauer Typ
_BitInt(N)hinzugefügt - Neue C-Bibliotheks-Header für arithmetische Operationen mit Overflow-Prüfung und Bitmanipulation hinzugefügt
- Berücksichtigung der Möglichkeit von 128-Bit-Typen auf modernen Architekturen
- Einschließlich wesentlicher Verbesserungen bei enum-Typen
- Neuer bitgenauer Typ
- Auch weitere neue Konzepte aus C23 sind enthalten
- Die Konstante
nullptrund ihr zugrunde liegender Typ - Syntax-Annotationen über attributes
- Werkzeuge für typgenerische Programmierung, darunter
autoundtypeof {}-Default-Initialisierung, die auch für Arrays variabler Länge giltconstexprfür benannte Konstanten aller Typen
- Die Konstante
- Das neue Material behandelt außerdem zusammengesetzte Ausdrücke, Lambdas, „Internationalisierung“ und einen umfassenden Ansatz für Programmfehler
- Damit man mit C23 auf bestehenden Plattformen direkt starten kann, wurden ein Anhang und temporäre Include-Header ergänzt
- Mannings MEAP zur neuen Edition ist noch offen
- MEAP: https://www.manning.com/books/modern-c-third-edition
- Der endgültige Veröffentlichungstermin der C23 Edition in der Manning-Version ist noch nicht bekannt
1 Kommentare
Meinungen auf Hacker News
Anders als die Speicherreihenfolge auf meinem Rechner, Little Endian, heißt die Variante, bei der die höherwertige Darstellung zuerst kommt, Big Endian. Zu sagen, beides sei auf modernen Prozessoren verbreitet, wirkt etwas übertrieben, weil außer s390x kaum noch etwas übrig ist.
Jetzt kommen bestimmt gleich die Kommentare zu den allseits beliebten Nischen-/aussterbenden Big-Endian-Architekturen.
Wie in einem anderen Top-Kommentar gesagt: „modern“ heißt nicht zwingend beliebt oder weit verbreitet.
AIX und IBM i sind vielleicht nicht so aktiv wie IBM-Mainframes, aber AIX kann man als lebendiger ansehen als Solaris oder HP/UX, erst recht im Vergleich zu den vielen kommerziellen Unix-Systemen von früher. Auch IBM i hält sich gerade so, ist aber deutlich lebendiger als konkurrierende Legacy-Midrange-Plattformen wie HP MPE, deren Vendor-Support offiziell beendet wurde.
Der wichtigste Aspekt von C ist Portabilität. Der Kern ist, von kleinen Mikrocontrollern bis zu nahezu jeder Computing-Plattform zu reichen; ich frage mich, ob eine neue C-Version in diesem Maß übernommen wird.
Wenn ich Cutting Edge nutzen wollte, würde ich eher C++2x oder Rust statt C wählen. Übersehe ich etwas? Mich interessiert, welchen Vorteil dieses sogenannte moderne C bringt.
Für Cutting Edge würde ich Zig empfehlen. Die Sprachkomplexität ist viel geringer als bei modernem C++ und Rust. Ein weniger offensichtlicher positiver Nebeneffekt von C23 ist, dass Syntax wie
... = {}und{0}stärker an C++ angeglichen wird, sodass es für Maintainer von C-Bibliotheken weniger mühsam wird, Leute zu unterstützen, die C-Code mit einem C++-Compiler bauen wollen.0bzum Beispiel ist in der Mikrocontroller-Welt weit verbreitet.Mikrocontroller-Toolchains bauen meist auf GCC auf und bekommen solche Features kostenlos dazu. Es gibt immer noch proprietäre C-Compiler, die hinterherhinken, aber sie sind nicht mehr so wichtig wie vor 20 Jahren.
Wenn man nicht Embedded oder eine sehr breite Menge von Architekturen als Ziel hat, gibt es auch keinen Grund, ab heute kein C23 zu verwenden.
thread_local-Specifier wird bereits auf einigen Mikrocontroller-Plattformen genutzt, war vor C11 aber völlig illegal. Trotzdem vereinfacht er Speicherverwaltung in Thread-Umgebungen erheblich.Gibt es dafür einen Grund, extra in die C++-Welt zu wechseln?
Persönlich machen Dinge wie
guard,defer,auto,constexprundnullptrC für mich deutlich komplexer. Ich wähle C, weil ich Einfachheit brauche; wenn ich Komplexität will, würde ich normalerweise C++ wählen, auch wenn ich das eigentlich nicht will, oder lieber Go — und auf dem Server vielleicht Elixir._BitInt(N)ist auch hässlich und erinnert mich an_Bool, das jetzt zum Glückboolgeworden ist.constexprundnullptrriechen sehr stark nach C++. Trotzdem ist Modern C ein hervorragendes Buch, und für C99, an dem ich weiter festhalten will, hat es mir gute Dienste geleistet.NULLfalsch ist, beantwortet sich dank eines der wenigen Vorteile der ISO-Standardisierung, wenn man die zugehörigen Dokumente liest: https://wg21.link/p2312Kurz gesagt: Wenn man ein
NULL-Argument an ein type-generic Macro übergibt, können überraschende Ergebnisse entstehen, und der Status von bedingten Ausdrücken wie(1 ? 0 : NULL)und(1 ? 1 : NULL)hängt davon ab, wieNULLdefiniert ist. Außerdem kann es schwerwiegende Folgen haben,NULLan eine variadische Funktion zu übergeben, die einen Pointer erwartet. Auf vielen heutigen Architekturen habenintundvoid*unterschiedliche Größen; wennNULLeinfach0ist, wird also ein Argument mit falscher Größe an die Funktion übergeben.Es ist ähnlich wie beim Hausbau. Hammer und Schraubendreher sind sehr einfach, ein Kran ist extrem komplex, aber der Kran macht das Hausbauen einfacher. Wenn man ein Haus nur mit Hammer und Schraubendreher bauen will, muss man einen enorm komplexen Ablauf entwerfen.
Bei Programmiersprachen ist es genauso. Einen generischen Container in C++ zu bauen ist trivial, in C dagegen sehr schwierig. Man kann es mit
void *und manuellen Casts bis zu einem gewissen Grad nachahmen, aber das ist umständlich, fehleranfällig und macht den Code komplexer.Bei
std::sortundqsortist es dasselbe. Durch die Stärke von Templates und Funktionsobjekten ist die Implementierung einfacher und schneller. Man muss keinvoid *übergeben und zur Laufzeit dereferenzieren, und der Vergleich kann direkt in die Funktionsdefinition wandern. Es gibt keinen indirekten Aufruf, keine Übergabe über den Stack, und die Vergleichsfunktion kann sogar inline werden. Sprachkomplexität bedeutet nicht Implementierungskomplexität.autoist vor allem nützlich, wenn man mit type-generic Macros arbeitet, aber in normalem Code sollte man es besser nicht verwenden. Ich hoffe, man vermeidet den Wahnsinn à la almost always auto, der eine Zeit lang in der C++-Welt in Mode war.Leider gibt es zwischen Compilern kleine Unterschiede. Soweit ich mich erinnere, implementiert Clang das C++-artige
auto, während GCC das C-artigeautoimplementiert, sodass es beiauto-Pointern subtile Unterschiede gab. Ich weiß nicht, ob das inzwischen behoben wurde._BitInt(N)verwendet man normalerweise nicht direkt, sondern legt pertypedefdie benötigte Breite fest, zum Beispieltypedef _BitInt(2) u2;. Hässliche Syntax wie_Bist nötig, weil Kombinationen aus Unterstrich und anschließendem Großbuchstaben im C-Standard reserviert sind, damit kleine Ergänzungen der Sprache nicht mit bestehendem Code kollidieren. Der Name_Boolhat denselben Grund. Soweit ich weiß, istdefertatsächlich nicht in C23 gelandet.In der alten Definition war nicht einmal festgelegt, ob
NULLein Zeiger oder eine Ganzzahl ist. Auf Plattformen, die der Posix-Anforderung((void*)0)nicht folgen, war das deshalb eine Falle, die weder Zeigertyp noch -größe hatte.Dass
constexprundnullptrnach C++ riechen, liegt vermutlich daran, dass sie aus C++ zurückimportiert wurden.NULLkann man trotzdem weiterhin verwenden; nach außen hin scheint es aber alsnullptrneu definiert worden zu sein.execlp("echo", "echo", "Hello, world!", NULL);Dieser Code hat diesen Bug nicht:
execlp("echo", "echo", "Hello, world!", nullptr);Das hier ist ebenfalls in Ordnung:
execlp("echo", "echo", "Hello, world!", (char *)NULL);Ich wollte fragen, ob es eine gute Liste von C-Büchern gibt, habe die Antwort dann aber selbst gefunden. Hier wird Modern C als Mittelstufe eingeordnet.
https://stackoverflow.com/questions/562303/the-definitive-c-...
Als moderne C-Begleiter zu K&R halte ich Ben Klemens’ 21st Century C und Kings C Programming: A Modern Approach für zugänglichere Alternativen.
Persönlich finde ich Effective C besser als Modern C. Modern C ist sehr streng; es fühlt sich an, als lese man eine kommentierte Sprachspezifikation, was für Experten nötig sein mag, für jemanden wie mich, der C eher locker nutzt, aber langweilig zu lesen ist.
Einige von Metawares High-C-Erweiterungen gefallen mir ziemlich gut.
https://news.ycombinator.com/item?id=41647843
https://news.ycombinator.com/item?id=38938402
Ich verwende seit über einem Jahr modernes C++ für ein persönliches Projekt, einen Sprachinterpreter, denke wegen der mentalen Belastung durch C++ und der Tooling-Probleme aber immer wieder darüber nach, auf C umzusteigen. Visual Studios IntelliSense funktioniert mit C++20-Modulen immer noch fast gar nicht, und wegen der Fehlentwicklungen der Sprache wird zu viel in Interfaces gedrückt, wodurch auch die Kompilierzeiten hässlich werden.
Andererseits habe ich mich so sehr an Klassen, Member-Funktionen, generische Programmierung und Namespaces gewöhnt, dass ich wohl schon in der Falle sitze.
Hast du für diesen Zweck C# in Betracht gezogen? Visual Studio passt deutlich besser zu C#.
Wenn man in macOS Preview in der Seitenleiste auf Links im Inhaltsverzeichnis klickt, funktionieren sie nicht richtig.
Es ist erst ein paar Jahre her, dass ich mich bei einer von mir gepflegten Library darauf verlassen konnte, dass alle C-Compiler C99 unterstützen: https://github.com/eyalroz/printf
Doch kaum waren ein paar Jahre vergangen, wurde unweigerlich ein Issue eröffnet, das wegen irgendeiner uralten Embedded-Toolchain C89-Kompatibilität verlangte. C23 ist also schön und gut, aber irgendwie fühlt es sich an wie: Reden wir in 20 Jahren noch einmal darüber.
Kann jemand einen Artikel verlinken, der praxisnah erklärt, warum C faktisch bei C99 stehen geblieben ist? Unter den Projekten, über die man sprechen kann, nutzen kaum welche Features nach C11.
Weil C über Jahrzehnte praktisch eingefroren war, scheint sich die Nutzerschaft selbst in Richtung jener Leute selektiert zu haben, die C so mögen, wie es ist, und denen die Unterstützung uralter Sammelsurium-Compiler nichts ausmacht. Wer die Geduld verloren hatte oder eine Sprache des 21. Jahrhunderts wollte, ist zu C++/Rust/Zig usw. abgewandert.
Um 2010 herum war MSVC noch sehr wichtig, was aus einer heutigen Perspektive seltsam klingt, in der die meisten Entwickler offenbar zu Linux gewechselt sind. Andererseits gibt es auch nicht viele Projekte, die C11-Features unbedingt brauchen. C11 hat C99 VLAs auch wieder weggenommen, was kein besonders bedauerlicher Verlust war. C23 könnte die erste Version seit C99 sein, für die sich ein Upgrade vieler C-Codebasen tatsächlich lohnt.