Bugs – unerwünscht! Kodierungsregeln helfen bei Fehlervermeidung im Embedded-C-Code

Ein C-Kodierungsstandard beseitigt die Fehler in der Embedded-Software.
Ein C-Kodierungsstandard beseitigt die Fehler in der Embedded-Software.

Bis zu 100 Millionen Code-Zeilen kann ein heutiges Premiumfahrzeug enthalten. Pro 1000 Zeilen Code können etwa 20 bis 30 Bugs auftreten. Ein C-Kodierungsstandard –auf gängige Sprach-Features und Entwicklungs-Werkzeuge gestützt – hilft hier, die Fehler in Embedded-Software zu reduzieren.

Der Software-Gehalt der Fahrzeuge hat in den letzten Jahren exponentiell zugenommen. Schätzungen besagen, dass ein modernes Fahrzeug der Premiumklasse bis zu 100 Millionen Code-Zeilen enthalten kann. Dieser Code läuft auf einer Vielzahl miteinander interagierender Subsysteme, deren Palette von Infotainment-Systemen, Fensterhebern und der Klimaanlage bis zu überaus kritischen Anwendungen wie dem Motormanagement und Sicherheitssystemen reicht. Viele dieser Subsysteme werden vom jeweiligen Autohersteller entwickelt, doch eine große Zahl stammt von Zulieferern oder auch von unabhängigen Anbietern auf dem Zubehörmarkt.

Standards im Automotive-Bereich

In der Automobilindustrie setzt sich eine Reihe von Standards durch, zu denen neben dem bereits gut etablierten CAN-Bus auch die Automotive Open System Architecture (AUTOSAR, Bild 1), der MOST-Standard (Media Oriented Systems Transport) und die ISO-Norm 26262 gehören. Während die drei ersten Standards mit der externen Interaktion sowie der Vernetzung innerhalb des Fahrzeugs zu tun haben, enthält die Norm ISO 26262 Anforderungen in Sachen Sicherheit und Zuverlässigkeit.

Es ist wichtig, dass Applikationen, die von verschiedenen Zulieferern, aber auch von unterschiedlichen Gruppen eines Herstellers kommen, diesen Normen entsprechen. Allerdings verlangt nur ISO 26262 die Anwendung klar definierter Kodierrichtlinien zur Vermeidung von Fehlern, die im Code lauern und unter Umständen lebensbedrohende Fehlfunktionen auslösen können (Bild 2).

Notwendig ist deshalb ein Embedded-C-Kodierungsstandard, den alle Teams und Teammitglieder, die an der Entwicklung dieser interaktiven, vernetzten Systeme arbeiten, befolgen und verstehen können. Das ist deshalb besonders wichtig, weil die verschiedenen Teams und Zulieferer mit unterschiedlichen Entwicklungswerkzeugen, Compilern und Analyse-Tools arbeiten. Aus diesem Grund ist es zwingend erforderlich, auf der Kodierungsebene eine einheitliche Basis zu schaffen.

Vorteile eines Kodierungsstandards

Es bringt zahlreiche Vorteile mit sich, wenn ein Team oder ein Unternehmen einen Kodierungsstandard anwendet. Unter anderem verbessert sich die Lesbarkeit und Portierbarkeit der Software, die sich dadurch kostengünstiger pflegen und wiederverwenden lässt. Darüber hinaus kommt ein Kodierungsstandard einem Team von Software-Entwicklern und dem gesamten Unternehmen zugute, weil die einzelnen Teammitglieder weniger Zeit aufwenden müssen, um die Arbeit ihrer Kollegen zu verstehen oder zu prüfen.

Viel zu lange unbeachtet blieb jedoch einer der größten potenziellen Vorteile: So kann die Anwendung eines Kodierungsstandards dazu beitragen, die Software fehlerfrei zu machen. Es ist billiger und einfacher, das Einschleichen von Fehlern im Code von vornherein zu vermeiden, als diese Fehler nachträglich aufzudecken und zu beseitigen. Eine entscheidende Strategie besteht deshalb im Schreiben von Code, bei dem der Compiler, der Linker oder ein Statische-Analyse-Werkzeug in der Lage sind, Fehler automatisch zu vermeiden, indem die Bugs beseitigt werden, noch bevor der Code für die Verarbeitung freigegeben wird. Wichtig ist zweifellos die Verwendung von Tools, die die Konformität zu den oben erwähnten Standards verifizieren und zertifizieren. Eine solche Zertifizierung bietet jedoch noch keine Garantie, dass der fragliche Code fehlerfrei ist.

Es gibt diverse Ursachen für Fehler in Software-Programmen. Der ursprüngliche Programmierer selbst erzeugt bereits einige der Fehler, die teilweise zunächst im Dunklen bleiben und erst Monate oder gar Jahre später zu Tage treten. Weitere Bugs resultieren aus Missverständnissen auf Seiten der Personen, die den Code später pflegen, erweitern, portieren und/oder wiederverwenden.

Anzahl und Tragweite der vom ursprünglichen Programmierer eingebrachten Fehler lassen sich durch disziplinierte Einhaltung bestimmter Kodierungspraktiken reduzieren. Dabei kann es sich beispielsweise um die strikte Platzierung von Konstanten auf der linken Seite einer jeden Äquivalenzprüfung (==) handeln.
Der ursprüngliche Programmierer kann auch die Anzahl und Tragweite der Bugs beeinflussen, die von den für die Programmpflege zuständigen Programmierern eingebracht werden. Zum Beispiel stellt die angemessene Verwendung portierbarer Integer-Datentypen fester Breite wie int32_t sicher, dass künftige Portierungen des Codes auf einen neuen Compiler oder Zielprozessor zu keinem unerwarteten Überlauf führen.
Auch die Anzahl und Schwere der Fehler, die auf die für die Programmpflege zuständigen Programmierer zurückzuführen sind, lassen sich durch disziplinierte Anwendung konsistenter Kommentierungs- und Stil-Praktiken verringern. Auf diese Weise fällt es jedem Mitarbeiter eines Unternehmens leichter, die Bedeutung und richtige Anwendung von Variablen, Funktionen und Modulen zu verstehen.

Verfügbare C-Kodierungsstandards

Im Laufe der Jahre sind viele Kodierungsstandards entstanden, von denen einige speziell auf die Verwendung der C-Sprache für die Firmware-Entwicklung abzielen. Ein Beispiel hierfür sind die „Guidelines for the Use of the C Language in Safety-Critical Systems” der MISRA. Die Autoren des sogenannten MISRA-C-Standards wissen um die Risiken beim Design sicherheitskritischer Systeme, und ihre Richtlinien grenzen die C-Sprache auf eine sicherere Teilmenge ein.
Obwohl sich Firmware-Codierungsstandards und MISRA-C gelegentlich überschneiden, konzentrieren sich Kodierungsstandards allzu häufig auf stilistische Vorlieben. Dabei wird die Chance, an der Reduzierung des Fehleraufkommens mitzuwirken, leider vertan. MISRA-C dagegen bietet zwar hervorragende Hilfestellung bei der Eliminierung von Bugs, enthält dafür aber nur sehr wenig Hinweise im Hinblick auf alltägliche Stilfragen. Stilistische Unterschiede aber können die Ursache für Verständnisprobleme sein, aus denen wiederum Fehler resultieren können.
Der „Barr Group Embedded C Coding Standard” wurde mit dem Ziel entwickelt, diese Lücke zu schließen. Der Kodierungsstandard wurde von Anfang an mit der Zielsetzung ausgearbeitet, Firmware fehlerfrei zu halten. Jede einzelne Regel wurde im Hinblick auf dieses Ziel optimiert. Darüber hinaus fanden die nachfolgend aufgelisteten Leitprinzipien Einsatz. Deren Zweck ist es, Konflikte im Zusammenhang mit Aspekten, die von einzelnen Teammitgliedern gelegentlich als persönliche stilistische Vorlieben angesehen werden, zu beseitigen:

  • Die einzelnen Programmierer sind nicht Eigentümer der von ihnen geschriebenen Software. Die gesamte Software-Entwicklung erfolgt vielmehr als Auftragsarbeit für den jeweiligen Arbeitgeber oder Klienten, und deshalb sollte das finale Produkt auf fachmännische Weise erstellt werden.
  • Positiv oder negativ (tatsächlich meistens negativ) zu bewerten ist die Tatsache, dass die C-Sprache gemäß ANSI/ISO-Standard ein erhebliches Maß an Variabilität zulässt, was die Entscheidungen der Compiler-Implementierer betrifft. Diese vielen sogenannten „Implementierungs-definierten“, „nicht spezifizierten“ und „undefinierten“ Verhaltensweisen haben gemeinsam mit regionalspezifischen Optionen zur Folge, dass sich Programme, die aus identischem C-Code kompiliert wurden, zur Laufzeit sehr unterschiedlich verhalten können. Diese Grauzonen in der Sprache schränken die Portierbarkeit nicht sorgfältig ausgearbeiteter C-Programme erheblich ein.
  • Zuverlässigkeit und Portierbarkeit des Codes sind wichtiger als die Verarbeitungseffizienz oder der Komfort für den Programmierer.
  • Die MISRA-C-Richtlinien wurden sorgfältig erstellt und sind eine genaue Betrachtung wert. Bei den wenigen Aspekten, bei denen die Barr Group anderer Meinung ist als die MISRA-C-Richtlinien, wird das deutlich gemacht. Selbstverständlich steht es den Anwendern des Kodierungsstandards der Barr Group frei, zusätzlich auch die weiteren MISRA-C-Regeln anzuwenden.
  • Im Interesse einer effektiven Fehlervermeidung müssen Kodierungsstandards durchsetzbar sein. Wenn zwei oder mehr konkurrierende Regeln auf ähnliche Weise in der Lage sind, Fehler zu vermeiden, aber nur eine dieser Regeln automatisch durchgesetzt werden kann, wird die Anwendung der besser durchsetzbaren Regel empfohlen.