Code, der auf Plattformen im Embedded-Bereich zur Ausführung kommt, muss teilweise stringente Anforderungen erfüllen. Neben den eingeschränkten Ressourcen spielt zum Beispiel auch die Art der Speicherverwaltung eine Rolle. Die Vermeidung bestimmter Sprachmerkmale ist deshalb immer zu beachten.
Dynamische Speicherverwaltung
In der Embedded-Programmierung wird dynamische Speicherverwaltung eher zurückhaltend verwendet. Das hat hauptsächlich damit zu tun, dass aufgrund der Fragmentierung des Speichers, die mit der Zeit auftritt, die Operationen nicht deterministisch ablaufen. Die Implementierungen von new und delete können zwar, je nach Compilerhersteller, besser sein als ihre C-Gegenüber malloc und free, aber auch hier wird der Speicher im Laufe der Zeit fragmentiert.
Der Speicherbedarf eines Steuergerätes richtet sich oft an einem Use-Case aus, für den ein Worst-Case-Szenario definiert ist. Deshalb ist es meist möglich, das System mit einer statischen Speicherverwaltung aufzusetzen. Dies minimiert Fehlerquellen und erhöht den Determinismus der Anwendung.
Ausnahmenbehandlung
Die Ausnahmenbehandlung ist ein sehr mächtiges Werkzeug zur Behandlung von Fehlern, aber für den Einsatz im Embedded-Bereich ungeeignet. Die Implementierungen unterscheiden sich je nach Compilerhersteller, sind aber mit erheblichem Speicher- und Laufzeit-Overhead verbunden [3]. Außerdem wird bei der Ausnahmenbehandlung oft eine dynamische Speicherverwaltung verwendet, und es ist sehr schwierig, die Laufzeit deterministisch vorherzusagen.
Testbarkeit von Embedded-Code
Einen nicht zu unterschätzenden Aufwand bei der Entwicklung von Embedded-Systemen stellen die Verfügbarkeit und der Reifegrad der jeweiligen Ziel-Hardware dar. Oftmals wird mit der prototypischen Entwicklung der Software schon begonnen, bevor die Hardware in ausreichender Stückzahl verfügbar ist. In der Serienentwicklung laufen die Entwicklungen von Hard- und Software dann parallel. Die Möglichkeit zu frühen, aussagekräftigen Tests, die auch auf dem PC laufen können, ist vor einem solchen Hintergrund extrem wichtig. In C ist es relativ schwierig und aufwendig, Software so auszulegen, dass sie einerseits mit der richtigen Hardware und den Treibern spricht, andererseits auf Test-Stubs zugreift. In C++ ist mit dem Konzept der abstrakten Basisklassen eine einfache Möglichkeit in der Sprache vorhanden, um Interfaces leicht austauschbar zu machen.
TestFoo() |
Listing 4. Der zu testenden Komponente TestFoo werden die Schnittstellen-Informationen als Argument übergeben. |
class CANTransceiverMock : |
Listing 5. Der CANTransceiverMock dient als Attrappe, um Teile der Software ohne die Ziel-Hardware testen zu können. |
![]() | Matthias Kessler studierte Informatik an der Fachhochschule München und arbeitet bei der BMW CarIT GmbH in München als Software-Entwickler. matthias.kessler@bmw-carit.de | ![]() | Oliver Müller studierte Maschinenbau und Informatik an der Technischen Universität München und arbeitet bei der BMW CarIT GmbH in München als Software-Entwickler. oliver.mueller@bmw-carit.de |
![]() | Gerd Schäfer studierte Informatik an der Universität Karlsruhe und arbeitet bei der BMW CarIT GmbH in München als technischer Projektleiter für Software-Projekte. gerd.schaefer@bmw-carit.de |