HLL

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

HLL steht für "High Level Language", also "Höhere Programmiersprache".

Vorweg: Die "richtige" oder gar "beste" (höhere) Programmiersprache gibt es nicht! Wer in Diskussionsforen danach fragt, wird regelmäßig religiöse Kriege auslösen. (Wer seine persönliche Lieblingssprache schon gefunden hat, kann sich den Rest dieses Beitrags schenken, insbesondere dann, wenn diese Sprache für den in seinem Projekt verwendeten Prozessor auch verfügbar ist.)

Assembler und HLLs

Anders als Assembler sind höhere Programmiersprachen in aller Regel nicht an einer bestimmten Hardware-Architektur ausgerichtet sondern verfolgen andere Ziele, wie etwa leichte Erlernbarkeit, Standardisierung, Portierbarkeit, Wartbarkeit, Abfangen bestimmter, "typischer" Programmierfehler usw..

Höhere Programmiersprachen erfordern Hilfsprogramme wie Compiler oder Interpreter. Compiler erzeugen den endgültigen Maschinencode für eine bestimmte Hardware. Im Bereich der Mikrocontroller-Programmierung wird der Compiler typischerweise ein "Cross-Compiler" sein, also auf einem anderen System (i.d.R. einem PC) laufen als das System, für welches Maschinencode erzeugt wird. Interpreter sind Programme, die auf dem Zielsystem laufen und die mit der HLL formulierten Programmanweisungen direkt oder in Form eines Zwischencodes abarbeiten.

Kompilierung

Die Kompilierung ist zwar in aller Regel sehr viel aufwendiger als die Assemblierung (d.h. die Umsetzung der mnemonischen Abkürzungen eines Assembler-Programms in die "Bits und Bytes", die schließlich vom Mikrocontroller als Programm ausgeführt werden), bietet aber auch einen wesentlichen Vorteil: Dadurch, dass man lediglich den Compiler austauscht, lässt sich ein und dasselbe Programm für sehr unterschiedliche Zielsysteme kompilieren. In höheren Programmiersprachen geschriebene Programme sind somit leichter portierbar, eine einmal - in Form von Software-Entwicklung - getätigte Investition ist in einem sehr viel größeren Rahmen nutzbar (= Anzahl der möglichen Zielplattformen über unterschiedliche Architekturen und/oder lange Zeiträume hinweg betrachtet).

Vorurteile

Der Einsatz höherer Programmiersprachen im Bereich von Mikrocontrollern (= Embedded Programmierung) unterlag lange Zeit genau den selben Vorurteilen, die höheren Programmiersprachen vor ihrem Einzug in die Großrechnerwelt vor rund 30 Jahren entgegengebracht wurden: Zu ineffizient, zu speicherfressend, niemals als "Ersatz" für Assembler geeignet. Das war zumindest noch um 1990 herum die Meinung vieler "Experten" im hardwarenahen Bereich.

C

Vor etwas mehr als 10 Jahren setzte dann - zuerst bei leistungsfähigen Mikrocontrollern - ein Umdenken ein und die Programmiersprache C fand im embedded Bereich zunehmend Verbreitung. C ist heute für die meisten der größeren Mikrocontroller verfügbar und passt insofern recht gut zu Mikrocontrollern, als diese Sprache ursprünglich (Mitte der 1970er) entworfen wurde, um die Verwendung von Assembler bei der Implementierung des Unix-Betriebssystemkerns vermeiden zu können. Im Unterschied zu vielen anderen höheren Programmiersprachen ist daher in C der direkte Hardware-Zugriff kaum eingeschränkt.

C++

Mit der ständig zunehmenden Leistungsfähigkeit moderner Mikrocontroller und entsprechend komplexer werdender Software ist heute auch ein Trend zum Einsatz von C++ auf Mikrocontrollern zu beobachten. Bei C++ handelt es sich um eine (Anfang der 1980er entstandene) Erweiterung von C. Die über C hinausgehenden Teile von C++ liegen überwiegend im Bereich der "Objektorientierten Programmierung" (OOP), die heute als eines der vielversprechendsten Vorgehensmodelle zur Beherrschung komplexer Software-Architekturen gilt.

Basic, Pascal, ...

Darüberhinaus liefern die Anbieter einiger Controller z. B. auch Basic- oder Pascal-Compiler. Da für deren Nutzung im Bereich der Mikrocontroller-Programmierung der Standard-Umfang dieser Sprachen stets erheblich erweitert werden muss, spielen sie hauptsächlich für Hobbyprogrammierer oder sehr spezialisierte Entwicklungen eine Rolle. Das ansonsten in der Regel angestrebte Ziel einer verbesserten Portierbarkeit und Wiederverwendung von Software(-teilen) ist nicht annäherend in dem Maße zu erreichen wie mit C/C++.

Standardisierung

Da eines der wesentlichen Ziele beim Einsatz höherer Programmiersprachen der Investitionsschutz ist - Software(-teile) sollen leicht wiederverwendbar sein - ist eine Standardisierung wichtig. Diese sollte vorzugsweise durch unabhängige Gremien erfolgen und nicht als "de-facto"-Standard von einigen Anbietern für Compiler oder Tool-Chains, da ansonsten wiederum leicht eine Abhängigkeit von wenigen, marktbeherrschenden Firmen entstehen könnte.

ISO/ANSI-C

Seit 1989 gibt es für C einen ISO/ANSI-Standard, der 1999 nochmal geringfügig überarbeitet wurde. Spezielle, über diesen Standard-Sprachumfang hinausgehende Erweiterungen sind für den Mikrocontroller-Bereich nicht erforderlich. Man kann in C z. B. freizügig auf Speicheradressen und damit ohne Umwege direkt auf die Hardware, also Ports und andere Peripherie zugreifen. (Lediglich Interrupts, Einzelbitadressierung und I/O über spezielle Maschinenbefehle erfordern proprietäre Unterstützung des Compilers.) In C geschriebene Software ist damit vergleichsweise einfach - ganz oder in Teilen - auf andere Prozessoren portierbar.

ISO/ANSI-C++

Auch für C++ gibt es seit 1999 einen ISO/ANSI-Standard, womit C++ im Hinblick auf Portierbarkeit ähnliche Vorteile hat wie C. Bei der Weiterentwicklung und Standardisierung von C++ war eines der Ziele "You only pay for what you use", was auch weitgehend erreicht wurde (Ausnahme: Exceptions). Andererseits enthält der C++-Standard eine Vielzahl sehr komplexer Features, die zumindest 1999 noch kein Compiler vollständig implementiert hatte. Auch heute sind Compiler, die C++ gemäß der vollen ISO/ANSI-Spezifikation bieten, für Mikrocontroller noch rar, aber die "Lücken" hinsichtlich der Implementierung des Standard-Sprachumfangs werden ständig kleiner.

EC++

Mittels einer Hersteller-Initiative im Mikrocontroller-Bereich wurde dem sehr komplexen ISO/ANSI-Standard für C++ eine "abgespeckte" Variante nachgeschoben, "EC++" genannt (= embedded C++). Dieser enthält im Wesentlichen die "langjährig erprobten" Sprachfeatures von C++. Compiler, welche den EC++-Sprachumfang bieten, sind für die meisten der etwas größeren Mikrocontroller verfügbar. Einige Compiler bieten darüberhinaus Mischformen zwischen ISO/ANSI-C++ und EC++ und erlauben beispielsweise das Ein-/Ausschalten bestimmter Sprachfeatures in der projektspezifischen Konfiguration. (So lassen sich etwa Exceptions - und der damit unvermeidlich einhergehende Overhead - ausschalten, wenn dieses Feature in einem Projekt nicht benötigt wird.)

Vergleiche

Um zu entscheiden, welcher Programmiersprache in welchem Fall der Vorzug gegeben werden sollte, kann auch der direkte Vergleich eine Hilfe sein.

Eine andere, erfrischende Sichtweise bietet der Forenbeitrag Re: Welche Programmiersprache empfehlt ihr mir? (Windowsprogrammierung) von Yalu.

Assembler vs. C

Hauptartikel: ASM vs C

Keine Frage: Bei intimer Kenntnis einer Hardware-Architektur und der zugehörigen Maschinensprache wird ein Assembler-Experte den von einem Compiler aufgrund eines C-Quelltextes erzeugten Code i.d.R. schlagen - oft allerdings nur marginal im Bereich einiger weniger Prozent. So wichtig diese paar letzten Taktzyklen auch in einer zeitkritischen Interrupt-Routine sein mögen, so sehr kommt bei umfangreicheren Projekten die Tatsache ins Spiel, dass eine einzelne Person kaum den Überblick über das gesamte Programm haben wird. Damit ist ein Compiler in einer sehr viel besseren Position, Heuristiken und andere Techniken anzuwenden, so dass das Kompilier-Ergebnis in der Qualität "lokal hand-optimiertem" Code nicht nachstehen muss sondern diesen sogar in der Summe häufig übertreffen wird.

Im Übrigen ist es auch beim Einsatz von C nützlich und hilfreich, gewisse Grundlagenkenntnisse hinsichtlich die Architektur des verwendeten Mikrocontrollers zu besitzen und insbesondere zu verstehen, wie die Konstruktionen der Hochsprache C schließlich in Maschinensprache abgebildet werden. Man sollte Assembler wenigstens lesen können, um das Kompilat, besonders in der Kennenlernphase des Kompilers, zu überprüfen und daraufhin ggf. geeignetere Kontrollstrukturen, kürzere Zeiger u. ä. einzusetzen.

C vs. C++

Hauptartikel: C vs C++

Da C quasi als "Teilmenge" in C++ enthalten ist, sollte sich jedes C-Programm auch mit einem C++-Compiler übersetzen lassen und gemäß dem oben zitierten Leitsatz ("You only pay for what you use") sollte der erzeugte Machinencode in diesem Fall nicht aufwändiger sein als bei der Übersetzung mit einem C-Compiler. Dies ist tatsächlich so - auch in C++ geschriebene Programm sind nicht grundsätzlich "ineffizienter" als reine C-Programme. Das gilt um so mehr, als viele Projekte, die "offiziell" in C++ abgewickelt werden, diese Sprache nur als "besseres" C nutzen, also viele der in C++ möglichen Konstruktionen überhaupt nicht verwenden.

Mit zunehmender Nutzung der über C hinausgehenden Erweiterungen von C++ sollten die Beteiligten allerdings auch ein TIEFES Verständnis dafür besitzen, wie C++ in C abgebildet wird. Ansonsten werden - letzten Endes aus Unkenntnis - leicht Programme entstehen, die deutlich weniger performant sind oder mehr (Speicher-) Ressourcen benötigen als äquivalenter C-Code. Es wäre allerdings falsch, diesen Effekt dann der Verwendung von C++ zuzuschreiben ...

EC++ vs. ISO/ANSI-C++

Dem EC++-Standard ist es einerseits gelungen, einen sofort umsetzbaren C++-Standard für die Embedded-Programmierung zu definieren, lange bevor C++-Compilern die Marktreife erreicht haben, die den ISO/ANSI-Standard voll implementieren. An der langfristigen Bedeutung des EC++-Standards müssen allerdings Zweifel angemeldet werden. Zwar mag das Ausklammern von Exceptions und die damit verbundenen Einsparungen für Programme, die Exceptions überhaupt nicht benutzen, noch längere Zeit interessant sein. Das Fehlen von Templates nimmt aber wesentliche und gerade im Bereich der Embedded-Programmierung nützlich erscheinende Freiheitsgrade, wenn es um die Code-Konfiguration zwischen Implementierungs- und Kompilierungs-Zeitpunkt geht.

C/C++ vs. Code-Generatoren

Auch wenn wie hier dargestellt C (schon heute) und C++ (vielleicht morgen) die dominierenden höheren Programmiersprachen bei allen größeren Projekten sind, in denen Mikrocontroller zum Einsatz kommen, sollte man Alternativen kennen und abwägen können. Hierzu gehören beispielsweise problemspezifisch entworfene "Little Languages" (oft relativ simple, interpretierte Datenstrukturen, evtl. unterstützt durch C-Makros) oder durch Code-Generatoren erzeugte Programmteile. Für in einigen Domänen häufig wiederkehrende Aufgabenstellung - etwa UI/GUI (= User Interface / Graphical User Interface), Realisierung von FSMs (= Finite State Machines) u.ä. - stellen solche Ansätze oft die in jeglicher Hinsicht effizienteste Vorgehensweise dar.