C und Bare-Metal-Systeme. Diese schier symbiotisch wirkende Kombination scheint seit eh und je gesetzt. 2004, 2014 und auch 2024. Dabei passt C als letzte moderne imperative Programmiersprache einfach sehr gut in die Ausführungslogik strukturierter Bare-Metal-Basis-Software.
Am besten fasst man Bare-Metal-Software wie folgt zusammen: “Mache erst das, dann das und dann tu nichts - so lange bis du unterbrochen wirst.”
Nun mag das vor allem für zeitkritische (Stichwort RTOS, Zephyr) oder Plattform-basierte (platform.io, mbed) durchaus nicht mehr ganz so richtig sein, aber im Prinzip sind diese architektonischen Grundsätze aus Startup, Init, Scheduler und Interrupt Controller die treibenden Ideen hinter einer Software in C.
Und natürlich - so viel sei sicher - C wird noch sehr sehr lange um uns herummäandern und den einen oder anderen vermutlich überleben.
Aber: in Sachen Safety und Security müssen wir dringend über Alternativen nachdenken dürfen. Der logischste erste Gedanke ist da der an den “großen Bruder” C++.
Denn: C++ ist einfach eine bessere Programmiersprache. Punkt.
C++ hat sich im letzten Jahrzehnt kontinuierlich weiterentwickelt, insbesondere mit den bedeutenden Änderungen, die in C++ 11 und C++ 14 eingeführt wurden. Obwohl auch C verbessert wurde, gibt es keine lebhafte Support-Community und viele Teams, die mit C arbeiten, verwenden nach wie vor C99 als ihren bewährten Compiler.
Viele der alten Argumente, warum C++ in der Embedded-Entwicklung nicht funktioniert, sind heutzutage nicht mehr passend. Diese Argumente drehten sich oft darum, dass C++ den Code aufbläht, ineffizient ist und nicht so gut wie C auf Hardware zugreifen kann. Diese Behauptungen sind heute nicht mehr zutreffend und waren möglicherweise auch vor 10 Jahren schon nicht stichhaltig.
Auch in Sachen Sicherheit und Verlässlichkeit gibt es bei C++ spannende Sprachfeatures, insbesondere im SIL-Kontext. Die Vorhersehbarkeit von C kann zwar bei sicherheitskritischen Anwendungen ein Vorteil sein. Das Fehlen bestimmter Funktionen bedeutet jedoch, dass die Entwickler besonders vorsichtig sein müssen, um häufige Fallstricke wie Pufferüberläufe oder invalides Casting zu vermeiden. Gute statische Codeanalyse-Systeme wie Lint oder Sonarqube sollen genau diesen “Fallstricke” vorbeugen. Bei C++ hingegen sind Funktionen wie starke Typüberprüfung, Ausnahmebehandlung und RAII (Resource Acquisition Is Initialization) Teil der Grundüberlegung. Sie erfordern jedoch auch ein tiefes Verständnis, um in einem eingebetteten Kontext effektiv eingesetzt werden zu können.
Gründe, warum sich C++ in Embedded Systems-Projekten lohnt
Erweiterte Objektorientierung
C++ ermöglicht einen echten objektorientierten Ansatz, was bei der Entwicklung komplexer Systeme von Vorteil sein kann. Die Unterstützung von Klassen, Vererbung und Polymorphie ermöglicht eine klarere Strukturierung und Modularisierung des Codes.
Moderne Sprachfeatures
C++ bietet moderne Sprachkonstrukte wie Templates, Lambda-Ausdrücke und Ausnahmebehandlungen. Diese Features können die Entwicklung effizienter machen und zur Lösung komplexer Probleme beitragen. Ich persönlich schätze insbesondere Lambda-Ausdrücke, weil es imperative Sprachen um funktionale Programmierparadigmen erweitert.
#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned n) {
std::sort(x, x + n,
// Lambda expression begins
[](float a, float b) {
return (std::abs(a) < std::abs(b));
} // end of lambda expression
);
}
Standardbibliothek und Tools
Die umfangreiche Standardbibliothek von C++ bietet viele vordefinierte Funktionen und Klassen, die die Entwicklungszeit verkürzen können. Zudem gibt es eine große Auswahl an modernen Entwicklungstools und Bibliotheken.
Speichermanagement: C++ bietet mehr Kontrolle über das Speichermanagement, einschließlich der Möglichkeit der manuellen Speicherverwaltung und intelligenter Zeiger. C++ bietet mehrere Arten von intelligenten Zeigern, wie std::unique_ptr, std::shared_ptr und std::weak_ptr, die automatisch Speicher freigeben, wenn sie nicht mehr benötigt werden. Am Beispiel des Unique-Pointers kann man das sehr gut darstellen. std::unique_ptr ist ein intelligenter Zeiger, der exklusives Eigentum über das Objekt hat, auf das er zeigt. Wenn der unique_ptr aus dem Geltungsbereich herauskommt, wird das Objekt automatisch gelöscht.
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> uniquePtr(new int(20));
std::cout << *uniquePtr << std::endl;
// Kein manuelles Löschen notwendig
return 0;
}
Performance und Effizienz: Moderne C++-Compiler können Code generieren, der hinsichtlich Geschwindigkeit und Speichernutzung mit C vergleichbar ist. Ich habe ein Zitat im Kopf “There isn't much that's special about C. That's one of the reasons why it's fast.” Sicherheit, Speicherfunktionen und Effizienz gibt es eben nur mit erweiterten Sprachkonstrukten als dem strikten Imperativismus von C. Diese Thema wird seit eh und je heiß diskutiert. Es gibt spannende Beispiele auf YouTube ([1],[2],[3]), die kein klares Bild zeigen, das in Sachen Ausführungsgeschwindigkeit der einen oder anderen Sprache einen Vorteil zuordnen lässt.
Striktere Typisierung: C erlaubt mehr Flexibilität im Umgang mit Typen als C++. Diese größere Flexibilität kann in bestimmten Szenarien von Vorteil sein, birgt jedoch auch Risiken. C++ ist in dieser Hinsicht restriktiver und bietet daher Vorteile im Hinblick auf Sicherheit und Zuverlässigkeit, was besonders in sicherheitskritischen und sicherheitsrelevanten Kontexten wichtig ist.
Stärkung des architektonischen Denkens: Objektorientierung, Vererbung und Polymorphie in C++ ermöglichen eine stärkere Fokussierung auf thread- und datenorientierte Softwarearchitektur. Diese Konzepte fördern eine klarere Trennung von Verantwortlichkeiten und eine verbesserte Wiederverwendbarkeit von Code.
Modularität und Team-Kooperation: Die Verwendung von Klassen und Namespaces in C++ erleichtert die Parallelisierung der Entwicklungsarbeit. Dies ist besonders vorteilhaft in größeren Teams, da es eine bessere Organisation des Codes und eine klarere Strukturierung von Softwareprojekten ermöglicht. Man kann Entwickler zu Spaces, Klassen oder Objekten zuordnen. Das stärkt die Zusammenarbeit in einem ganz andren Maße, als es mit C jemals möglich wäre.
Kombinierter Einsatz von C und C++: In vielen Embedded-Projekten ist es möglich, C und C++ parallel zu nutzen. Bestehender C-Code kann durch geschicktes Refactoring und Cross-Compiling integriert werden, was den Übergang zu C++ erleichtert und gleichzeitig den Wert vorhandener Codebasen erhält. Gerade im Bereich Low-Level-Programmierung sind einzelne Teile C oder Assembler unverzichtbar. Sie können aber ohne großen Aufwand in C++-Programme integriert werden.
Talent Sourcing außerhalb der Elektrotechnik: Natürlich spielt auch das eine Rolle. C++ ist in der Informatik allgemein verbreiteter als C. Dies eröffnet Embedded-Unternehmen die Möglichkeit, Fachkräfte aus Bereichen wie der Spiele- und Anwendungsprogrammierung sowie aus Linux- und Grafik-Entwicklung zu rekrutieren. Dadurch kann der Pool an verfügbaren Talenten erweitert und neue Perspektiven und Fähigkeiten in das Unternehmen integriert werden.
Fazit
Ja, C++, mit seinen fortschrittlichen Funktionen und kontinuierlichen Entwicklungen, stellt in vielen Aspekten, insbesondere in Sicherheit und Effizienz, eine überlegene Alternative zu C dar. C++ fördert erweiterte Programmierkonzepte wie Objektorientierung und modernes Speichermanagement, die in der Embedded-Entwicklung zunehmend wichtig werden. Der Artikel betont auch die Möglichkeit, C und C++ in Embedded-Projekten zu kombinieren, um die Vorteile beider Sprachen zu nutzen und gleichzeitig den Talentpool zu erweitern. Für Unternehmen ist es eine Überlegung Wert, kleinere MVP-Projekte auf C++-Basis zu beginnen und die Sprache ganzheitlich auszurollen - gerade im Safety- und Security-Kontext.
Kommentieren