Ende 2022 schrieb Kris van Rens über den Stand von C++ zu dieser Zeit und seine Herausforderer. Eine Fortsetzung nach zwei weiteren Jahren.
Im Jahr 2022 zog Google aus Unzufriedenheit mit dem Entwicklungsprozess von C++ einen Großteil seiner Ressourcen aus der Arbeit an C++ und dem Clang-Compiler-Frontend ab. Als Alternative kündigte es das langfristige Projekt Carbon an, eine Nachfolgesprache, die eng mit C++ zusammenarbeiten kann. Dies und die darauf folgenden Ereignisse stellten einen Wendepunkt für C++ dar, da die Sprache wegen der angehäuften technischen Schulden und des relativ langsamen Entwicklungstempos ernsthaft kritisiert wurde. Von diesem Moment an, so schien es, hatte jeder eine (starke) Meinung und verkündete sie lautstark – die Menge an Kritik konnte vom C++-Komitee nicht länger ignoriert werden.
Ein weiterer Aspekt von C++, der unter Beschuss geraten ist, ist die fehlende Speichersicherheit. Speichersicherheit in einer Programmiersprache bezieht sich auf die Fähigkeit, Fehler im Zusammenhang mit unsachgemäßem Speicherzugriff, wie z.B. Pufferüberläufe, Use-after-free-Fehler oder baumelnde Zeiger, durch eingebaute Funktionen und Garantien in der Sprache selbst zu verhindern oder abzufangen. Dies kann zu allgemeiner Sprachsicherheit erweitert werden, bei der alle undefinierten Verhaltensweisen und nicht spezifizierte Semantiken aus der Sprache eliminiert werden. Sprachsicherheit ist ein Konzept, das auf einem Spektrum und nicht als binäre Eigenschaft definiert ist; einige Sprachen sind sicherer als andere. Beispiele für Sprachen, die als sicher gelten und dennoch ein relativ niedriges Niveau haben, sind Swift, Ada und Rust.
Nach der sprichwörtlichen Hitze des Sommers 2022 hat eine Reihe von Schlägen in Form von öffentlichen Empfehlungen zur Speichersicherheit sowohl C als auch C++ explizit ins schlechte Licht gerückt. Ende 2022 meldete sich zunächst die NSA mit einem White Paper zu Wort, in dem sie uns aufforderte, von C und C++ abzurücken. Dann begann die CISA (die US Cybersecurity Infrastructure Security Agency), sich für eine Roadmap zur Speichersicherheit einzusetzen. In den Jahren 2023 und 2024 verkündeten sogar das Weiße Haus und der US-Verbraucherbericht, dass wir die Speichersicherheit ernster denn je nehmen und zu speichersicheren Sprachen übergehen sollten. Es gab noch viele weitere Ereignisse, aber es genügt zu sagen, dass sie alle vom C++ Komitee nicht unbemerkt geblieben sind.
''C is quite a simple language; it’s easy to learn and get started with. However, it’s very hard to become advanced and proficient at it at scale.''
Zugegeben, einige der Bemühungen der Mitglieder des C++-Ausschusses, die öffentlichen Angriffe zu entkräften, wirkten ein wenig verächtlich. Oft wurde die Speichersicherheit als „nur eines der vielen potenziellen Softwareprobleme“ heruntergespielt. Das klingt für mich sehr nach einem logischen Trugschluss. Sicher, viele Dinge können schief gehen, und eine sichere Sprache ist kein Allheilmittel. Allerdings haben sich die Anforderungen an die Softwareentwicklung in den letzten vierzig Jahren drastisch verändert, und heute ist die Speichersicherheit ein gelöstes Problem für viele andere Sprachen, die im gleichen Anwendungsbereich eingesetzt werden können. Offiziell hat die ISO-Arbeitsgruppe 21 (WG21) die Studiengruppe 23 (SG23) für „Safety and Security“ eingesetzt, deren Aufgabe es ist, die besten Wege zu finden, um C++ zu einer sichereren Sprache zu machen und gleichzeitig andere Einschränkungen wie die Abwärtskompatibilität einzuhalten – gar nicht so einfach.
Unbestreitbare Kluft
Ich habe in den letzten Jahrzehnten mit verschiedenen Programmiersprachen gleichzeitig in der Produktion gearbeitet. Was mir bei all meinen Erfahrungen mit C und C++ besonders auffällt, ist die schiere kognitive Belastung, die sie für Entwickler darstellen.
C ist eine recht einfache Sprache, die leicht zu erlernen ist und mit der man leicht anfangen kann. Es ist jedoch sehr schwer, sie in großem Umfang zu beherrschen und weiterzuentwickeln. Da es sich um eine einfache Sprache handelt, sind Sie gezwungen, viele wichtige fehleranfällige technische Aufgaben wie die Speicherverwaltung und die richtige Fehlerbehandlung manuell zu erledigen – wichtige Aspekte einer zuverlässigen, fehlerfreien Software. Es gibt zwar viele Kontrollmöglichkeiten auf niedriger Ebene, aber die Zeremonie und der kognitive Aufwand, um die Dinge richtig zu machen, sind einfach umwerfend.
Das Gleiche gilt weitgehend für C++. Es macht die Dinge besser, indem es Sie beim Schreiben von korrektem Code unterstützt, zum Beispiel mit der Standardbibliothek, die intelligente Zeiger für die Speicherverwaltung enthält. Allerdings macht es die enorme Komplexität der Sprache auch schwer, sie in großem Umfang korrekt zu verwenden.
Hinzu kommt, dass all diese Aspekte der Codierung in C und C++ keine Garantie dafür bieten, dass die Dinge nach der Kompilierung zuverlässig sind. Dies zwingt Entwickler dazu, sich mit bewährten Verfahren zu befassen, Compiler-Sanitizer und statische Analysatoren zu verwenden und umfangreiche Tests durchzuführen, nur um sicherzugehen, dass alles in Ordnung ist. Natürlich sollten die meisten dieser Aktivitäten Teil einer gesunden Denkweise von Softwareentwicklern sein, aber es ist schmerzlich zu erkennen, dass C und C++ die Anforderung, diese Arbeit zu erledigen, auf den Entwickler abwälzen, anstatt sie direkt in der Sprache zu berücksichtigen. Die Entwicklung einer Sprache ist, wie jede technische Herausforderung, eine endlose Abfolge von Kompromissen, aber es gibt eine unbestreitbare Lücke zwischen den Fähigkeiten der ‚alten Sprachen‘ und den aktuellen Bedürfnissen der Softwareentwicklung. Andere, neuere Sprachen zeigen, dass es möglich ist, diese Anforderungen zu erfüllen und gleichzeitig das Leistungspotenzial zu erhalten.
''New features improve the language but also inherently increase the already quite substantial complexity, while all the old footguns and dangers like undefined behavior are still there.''
Jahre entfernt
Die meisten Programmiersprachen werden im Laufe der Zeit ständig verbessert. In der Welt von C wird sich jedoch wahrscheinlich wenig bis gar nichts ändern. Für viele Projekte ist C daher heute nicht mehr die richtige Sprache, wenn Sie überhaupt noch Sicherheit wünschen. Es gibt Alternativen, die für den Zweck besser geeignet sind – wenn dies angesichts Ihrer Projektbeschränkungen und -präferenzen möglich ist.
Bei C++ sieht die Sache anders aus. Die WG21 bereitet sich derzeit auf die Veröffentlichung von C++26 vor, das enorme neue Funktionen mit sich bringen wird, darunter (höchstwahrscheinlich) Verträge, Executors und sogar statische Reflexion. Diese Funktionen werden mit Sicherheit die Spielregeln verändern, aber vor allem das Anwendungspotenzial der Sprache oder, im Falle von Verträgen, die Sicherheit und Korrektheit verbessern, allerdings auf Kosten der manuellen Arbeit des Entwicklers.
Neue Funktionen verbessern die Sprache, erhöhen aber auch die ohnehin schon beträchtliche Komplexität, während all die alten Fußangeln und Gefahren wie undefiniertes Verhalten immer noch vorhanden sind. Wenn Sie als Trainer Anfängern C++ beibringen, bleibt es zum Teil eine Übung, sie von den Fallstricken fernzuhalten – nicht wirklich eine natürliche, bequeme Art zu lehren oder zu lernen.
Das ‚Paralleluniversum‘ der Circle C++-Sprache zeigt, wie die scheinbar schwerfällige Syntax und Sprachdefinition von C++ immer noch in der Lage ist, viele andere großartige Funktionen wie echte Enumeratoren, Pattern Matching, statische Reflexion und sogar einen Borrow Checker zu integrieren. Leider ist diese bemerkenswerte Ein-Mann-Show von Sean Baxter kein standardisiertes C++ (und umgekehrt). Die Chancen sind gering, dass eine dieser hervorragenden Funktionen in absehbarer Zeit in das offizielle C++ aufgenommen wird.
Baxter hat auch einen „Safe C++“-Vorschlag, den er der Safety and Security Study Group im November letzten Jahres vorgelegt hat. Darin schlägt er vor, C++ um eine „rigoros sichere Teilmenge“ der Sprache zu erweitern, die die gleichen Sicherheitsgarantien bietet wie der Rust-Borrow-Checker. Ich begrüße diese Bemühungen, aber es bleibt abzuwarten, ob und in welcher Form dieser Vorschlag seinen Weg durch den oft träge erscheinenden Entwicklungsprozess der Sprache C++ finden wird. Die Arbeiten an C++26 haben sich weitgehend angenähert und C++29 ist noch ein paar Jahre entfernt. Hinzu kommt die Implementierungs-/Industrialisierungszeit dieser Spezifikationsversionen, bevor sie wirklich auf unseren virtuellen Werkbänken landen, und es könnte durchaus noch ein Jahrzehnt dauern – wenn wir Glück haben.
Grünere Weiden
Aber es ist noch nicht alles verloren. Das C++-Komitee leistet großartige Arbeit bei der Weiterentwicklung der Sprache, und der aktuelle Stand der Sprache und des Ökosystems ist besser denn je. Es ist nur so, dass die Kluft zwischen dem, was C++ heute bieten kann, und dem, was bei der Sicherheit der Systemprogrammierung und den integrierten Werkzeugen möglich ist, enorm ist.
Wenn ich ein paar Jahre in die Zukunft blicke, sehe ich nicht, dass diese Lücke geschlossen wird. Inzwischen stehen Sprachen wie Rust und Swift nicht mehr still. Es gibt in der Welt eine große Dynamik und ein früheres Engagement für C++, so dass die Industrie daran festhält, aber wie lange kann sie die Technologielücke aufrechterhalten, bevor Branchen oder Anwendungsbereiche zu grüneren Weiden wechseln?