Forum: Mikrocontroller und Digitale Elektronik C vs. C++ zur Mikrocontrollerprogrammierung - oder: Auf welche C++ Features lieber verzichten?


von Emil J. (mmgj)


Lesenswert?

Hallo Leute,

man liest ja oft, dass für Mikrocontroller C++ nur bedingt geeignet ist, 
da sehr viele Ressourcen in Anspruch genommen werden.

Im Prinzip bringt aber C++ doch nur Komplexität in den Maschinencode, 
sobald irgendwelche dynamischen Sprachfeatures verwendet werden!

Meine Frage nun:
Auf welche Sprachfeatures sollte ich lieber verzichten, welche kann ich 
ruhigen Gewissens einsetzen?

Eine kleine Liste, zu der ich mir Feedback wünsche:
Klassen und Vererbung/Polymorphie:
Stell ich mir jetzt überhaupt nicht schädlich vor. Sind ja im Prinzip 
nur Structs mit Funktionen.

Templates:
Ich denke, dass man Templates schon benutzen kann. Der Compiler baut ja 
die Klassen/Funktionen nur zusammen, wenn man das Template mit dem 
entsprechenden Typ auch benutzt.

Exceptions:
Hmm, schwer. Ich weiß nicht genau, wie sie intern funktionieren. Kann 
mir vorstellen, dass durch diese Abbruchsprungpunkte eine Menge 
Maschinencode generiert wird!?

Run Time Type Information (RTTI):
Hört sich auch nicht so light-weight an. Habe ich bisher kaum genutzt 
und es tut glaube ich im Mikrocontrollerbereich auch nicht sooo weh 
darauf zu verzichten.

Operator Überladung:
Ich glaube, das läuft alles im Compiler ab und dient nur der 
Programmier-Ergonomie. Da sollte nix besonders passieren, oder?


Bleiben jetzt noch Performance oder Ressourcen Nachteile von C++ 
gegenüber C?

Danke!

Gruß,
Emil

von cppler (Gast)


Lesenswert?

Also die meisten C++ Compiler die ich kenne legen eine Sprungtabelle für 
die Verwaltung der einzelnen Objekte an was mehr RAM erfordert.
Ansonsten kommt es sicherlich darauf an was erreicht werden soll.
Auf einem 8bitter macht C++ sicherlich wenig Sinn, wenn dagegen genügend 
RAM zur Verfügung steht sollte man schon alles verwenden was die Sprache 
hergibt.
Dafür ist es ja gemacht.

von Oliver (Gast)


Lesenswert?

Keins der von dir genannten Features (und auch keins der nicht 
genannten) benötigt im C++ (ernsthaft) mehr Resourcen  als in C, wenn du 
wirklich GENAU die selbe Funktionalität (!!!) implementierst.

Dazu ist die Gattung "Mikrocontroller" weit gefasst. Auf einem Tiny mit 
128 byte Ram ist manches schlicht nicht möglich, auf einem ARM mit 64kB 
Ram oder mehr nimmt man volles C++, ohne überhaupt darüber nachzudenken.

In diesem Sinne...

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Emil J. schrieb:

> man liest ja oft, dass für Mikrocontroller C++ nur bedingt geeignet ist,
> da sehr viele Ressourcen in Anspruch genommen werden.

µC gibt es von .. bis.
Daher: Das kann man so pauschal nicht sagen. Beschränken wir uns mal auf 
die kleinen, die mit wenig SRAM

> Im Prinzip bringt aber C++ doch nur Komplexität in den Maschinencode,
> sobald irgendwelche dynamischen Sprachfeatures verwendet werden!

Damit hast du dann auch schon dein Hauptkriterium: Alles was mit 
dynamischer Datenstruktur zu tun hat.
Leider beinhaltet das auch die std::string Klasse bzw. überhaupt die 
Container-Klassen.

> Eine kleine Liste, zu der ich mir Feedback wünsche:
> Klassen und Vererbung/Polymorphie:
> Stell ich mir jetzt überhaupt nicht schädlich vor. Sind ja im Prinzip
> nur Structs mit Funktionen.

Seh ich kein Problem. Virtuelle Funktionen brauchen zwar ein bischen was 
(die VTable), ist aber normalerweise nicht so schlimm und: die 
Alternative "Typ Member samt Cases" braucht auch Resourcen.

> Templates:
> Ich denke, dass man Templates schon benutzen kann. Der Compiler baut ja
> die Klassen/Funktionen nur zusammen, wenn man das Template mit dem
> entsprechenden Typ auch benutzt.

Kein Problem

> Exceptions:
> Hmm, schwer. Ich weiß nicht genau, wie sie intern funktionieren.

Da Exceptions funktionsübergreifend funktionieren kannst du deinen A... 
drauf verwetten, dass da dynamische Speicherallokierung im Spiel ist.

> Run Time Type Information (RTTI):
> Hört sich auch nicht so light-weight an. Habe ich bisher kaum genutzt
> und es tut glaube ich im Mikrocontrollerbereich auch nicht sooo weh
> darauf zu verzichten.

RTTI ist zwar manchmal ganz nett, da es aber auch lange Zeit in C++ ohne 
ging, braucht man die nicht so oft. Mit Polymorphie und virtuellen 
Funktionen kommt man schon sehr weit.

> Ich glaube, das läuft alles im Compiler ab und dient nur der
> Programmier-Ergonomie. Da sollte nix besonders passieren, oder?

Jep.

> Bleiben jetzt noch Performance oder Ressourcen Nachteile von C++
> gegenüber C?

Ist auf µC meistens nicht so sehr das Thema, aber die Stream-Library hat 
normalerweise stark aufgetragen. Braucht man aber bei typischen 
Steuerungsaufgaben eher selten :-)

von PittyJ (Gast)


Lesenswert?

Ich habe alles dynamische mit new/delete weggelassen. Dynamischer 
Speicher wollte ich in Interrupts nun doch nicht benutzen.
Bei C hätte ich dann wohl auch malloc gespart.

Den Rest von C++ habe ich benutzt.

von Emil J. (mmgj)


Lesenswert?

Danke für eure Beiträge.
Hat mir ein wenig die Angst genommen beim nächsten Projekt auf C setzen 
zu müssen :D

Emil

von Gerd E. (robberknight)


Lesenswert?

> Templates:
> Ich denke, dass man Templates schon benutzen kann. Der Compiler baut ja
> die Klassen/Funktionen nur zusammen, wenn man das Template mit dem
> entsprechenden Typ auch benutzt.

schon richtig. aber man kann mit einer unbedachten zeile code eine menge 
platz mehr benötigen. also vorsicht.

Wie Karl Heinz schon geschrieben hat: verzichte wenn möglich auf die 
iostreams. das mag zwar bequem zur ausgabe von debugging-code und 
ähnlichem sein, kostet dich aber ne riesenmenge an platz.

von JoarNe (Gast)


Lesenswert?

Des Weiteren gibt's Sprachfeatures, die praktisch sind und gar nichts 
kosten. Wie z.B. namespaces. Und ehrlich: Lieber brauche ich ein paar 
Bytes mehr und dafür ist der Code dann deutlich wartbarer.

von Exilant (Gast)


Lesenswert?

Ich hatte mal ein paar Versuche auf diversen atmegas mit c++ gemacht. 
Das geht schon alles, aber da man sich wirklich alles selbst basteln 
muss(new, stream-klassen, ...) war es ein bisschen witzlos.  Wer das 
mehr aus akademischem interesse macht haette sicher spass daran, aber 
wenn man einfach nur was steuern will ists eher nichts.  Was an wirklich 
anwendbarem (auf uCs mit 1000 Byte Ram) bleibt sind namespaces, consts 
und ganz selten mal ein template.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Oliver schrieb:
> Keins der von dir genannten Features (und auch keins der nicht
> genannten) benötigt im C++ (ernsthaft) mehr Resourcen  als in C, wenn du
> wirklich GENAU die selbe Funktionalität (!!!) implementierst.

Das stimmt einfach nicht.

Eine sinnvolle Definition von "GENAU die selbe Funktionalität" ist 
nämlich, daß sich die vom Compiler erzeugten Programme nicht anhand 
ihrer Seiteneffekte unterscheiden, d.h. z.B. wann/wie volatile Zugriffe 
(SFRs etc.) geschehen, wie auf globale Variablen zugegriffen wird, etc.

Wenn ich zum Beispiel Exceptions in C++ einerseits und setjmp/longjmp 
andererseits vergleiche, ist zweiteres wesentlich effektiver.  Schaut 
man sich zum  Beispiel an, wie groß der unwind-Code einer für AVR 
generierten libstdc++ ist, landet man bei ca. 30KiB.

Anderes Beispiel sind VTables. In C++ liegen diese im knapp bemessenen 
RAM.  In C ist es zwar etwas mehr Getippse, aber man kann LUTs ins Flash 
legen oder die paar Fälle codieren.

Nächstes Beispiel globale Konstanten.  Dazu folgenden Beispiel: Wir 
wollen eine effiziente Arithmetik und verwenden dazu Fixed-Point 
Arithmetik, weil unser µC keine Hardware-Unterstützung für float 
mitbringt.  Kalibrier-Werte und Lookup-Tabellen legen wird wegen des 
knappen RAMs ins Flash.

C: Wir verwenden den Fixed-Point Support von ISO/IEC TR 18037. 
Konstanten im Flash sind kein Problem.

C++: Weil wir "sauber" programmieren wollen, schreiben wir die 
Fixed-Point Arithmetik als Klasse(n) mit überladenen Operatoren. 
Ziemlich viel Handarbeit, weil C++ keine Obermenge von C ist.  Selbst 
wenn wir alle Funktionen zusammen haben und uns die Finger an 
(Inline)-Assembler wund geschrieben haben, ist die Performance immer 
noch schlechter als es der C-Compiler macht.  And jeder Stelle, wo 
Literale wie 3.14 verwendet werden, müssen wir hollisch aufpassen, daß 
wir uns nicht über die Hintertür doch wieder float-Arithmetik einhandeln 
-- etwa zur Konvertierung oder Multiplikationen/Divisionen zur Anpassung 
des Dezimalpunks/Nachkommastellen.

Dann die böse C++-Überraschung:  Für die Konstanten-Tabellen erzeugt der 
C++-Compiler ad-doc Konstruktoren und geht davon aus, daß die Tabellem 
im RAM stehen, und das selbst dann, wenn die Konstanten zu Compilezeit 
bekannt sind und die Klasse keine VTables braucht.  Um das zu umgehen, 
schreiben wir hässliche Makros, die die Kapselung unserer Fixed-Point 
Implementierung konterkarieren und fangen mit wüsten, geschachtelten 
Makros an, die es erlauben, die interne Darstellung der Zahlen zu 
Compilerzeit zu [de]serialisieren.

von temp (Gast)


Lesenswert?

Ich kann mich hier nur der Meinung von Johann L. anschließen. All die 
Sprachfeatures von C++ würde ich niemals auf einem kleinen Controller 
haben wollen. Und da zähle ich auch die Cortex M0-M4 dazu. Einen echten 
Vorteil kann ich nicht erkennen. Die Standard C++ Libs sind ohne 
dynamische Speicherverwaltung nicht möglich. Setzt man sie trotzdem ein, 
hat man überhaupt keinen Überblick über den Controller und dessen 
beschränkte Resourcen mehr. Ich tu mich mit den printf-Funktionen aus 
der newlib schon schwer und nehme dafür lieber was angepasstes kleines. 
Ich habe auch bei der PC-Programmierung nie verstanden was die C++ Std 
Lib für Vorteile bringen soll. Solche elementaren Sachen wie Strings, 
Container und Listen hat man irgendwann einmal für seine Bedürfnisse 
implementiert und kann sie immer wieder verwenden. Ich weiß gar nicht 
wie oft ich in den 21 Jahren, seit dem ich mit C++ auf dem PC unterwegs 
bin, den Compiler wechseln musste. Die Std C++ Lib habe ich noch nie 
gebraucht oder vermisst. Und mir damit viel Ärger erspart. Die eigenen 
String- und Containerklassen haben diese Zeit überlebt.
Vor 30 Jahren, als ich mit Assembler den Z80 programmiert habe, da 
kannte ich noch jedes Bit persönlich. Man hatte den Überblick über 
alles. Dieses gute Gefühl kann man heute auch noch auf den Controllern 
haben solange sie ohne Betriebssystem sind. Sobald aber Bibliotheken ins 
Spiel kommen von denen kaum der Stackbedarf bekannt ist, bzw. die 
dynamischen Speicher nach eigenem Belieben anfordern, hat man dieses 
Gefühl nicht mehr. Man kann ohne Frage C++ auch gut auf einem kleinen 
Controller einsetzen. Aber mehr in der Form C mit Klassen. Das macht den 
Code häufig wesentlich besser lesbar.
Wenn die Controller größer werden und ein richtiges Betriebssystem 
drunter liegt, sieht die Sache anders aus. Da kann man aus dem vollen 
Schöpfen wenn man unbedingt will. Da benutzt man das alles aber auch in 
der Art und Weise für das es mal erfunden wurde. Und ob ich nun von 98% 
oder 99% des Codes der da läuft keine Ahnung mehr habe spielt am Ende 
auch keine Rolle mehr.

von Oliver (Gast)


Lesenswert?

Johann L. schrieb:
> Schaut
> man sich zum  Beispiel an, wie groß der unwind-Code einer für AVR
> generierten libstdc++ ist, landet man bei ca. 30KiB.

Alles richtig. Allerdings war die Frage allgemein auf Mikrocontroller 
gestellt, und da ist die zugegebenermassen sehr ungünstige 
AVR-GCC-C++-Implementation wohl nicht zu verallgemeinern.

Oliver

von Chris (Gast)


Lesenswert?

Arduino nutzt C++.
Es gibt allerdings auch C Compiler welche zusätzliche C++ Features 
bereitstellen wie z.B. function overloading.
Was aber auch zu beachten ist, C hat einen anderen Namespace als C++.
Z.B. teilen enums und structs in C++ denselben Namespace als Variablen,
in C haben sie einen eigenen Namespace und die Zuweisung von Variablen
ist in C++ heikler, in dem Sinne daß eine Typenkorrektheit erzwungen 
wird.
Da gehen dann einfache Sachen nicht mehr, wie prüfen ob eine FP Zahl 
negativ ist und zwar als Integer, nicht als FP.

Function overloading ist ganz nett, ansonsten nein danke.
Aber wie bereits gesagt wurde, ist genügend Ram vorhanden, dann
ist C++ auch bedenkenlos aber mit Bedacht einsetzbar.

von Emil J. (mmgj)


Lesenswert?

Ich dachte an den Einsatz von C++ auf einem STM32.

Sprachfeatures, die ich schon sehr gerne benutzen würde, sind halt 
Funktionsüberladung (vielleicht Operatorüberladung), Templates, 
Exceptions und natürlich Klassen und Polymorphie.

Für die Rechenintensive Anwendung möchte ich einen STM32F4xx verwenden, 
der hat eine FPU.

Gruß,
Emil

von Oliver (Gast)


Lesenswert?

Mach es einfach...

Die C++-Sprachfeatures bringen dich da nicht um. Bei der Verwendung der 
std::xxx libs musst du halt aufpassen, da solltest du das verfügbare Ram 
im Auge behalten.

Oliver

von Bronco (Gast)


Lesenswert?

Ich programmiere meine AVR-Projekte inzwischen alle nur noch in C++, 
weil man mit Klassen meines Erachtens deutlich besser kapseln kann als 
in mit C-Modulen. Gerade Vererbung, Überladung etc. ist sehr elegant und 
kostet nicht mehr, als man für die entsprechende C-Implementierung auch 
gebraucht hätte.
Da ich auf laufzeit-komplexe Dinge wie Streams, Exceptions usw. 
verzichte, ist der Ressourcen-Bedarf zwischen C und C++ ziemlich 
identisch.
Man ist ja nicht gezwungen, alle C++ Features ausschöpfen zu wollen, man 
kann sich ja das sinnvollste aussuchen, und dann ist meines Erachtens 
C++ auch auf einem 8-Bitter absolut vorteilhaft.

von Dave (Gast)


Lesenswert?

Hi!

Wenn man sich jederzeit bewusst macht, was die Auswirkungen eines 
Sprach-Features auf den Maschinencode, Flash- und RAM-Verbrauch haben, 
ist C++ eine saubere Sache auch für einen Mikrocontroller mit wenig 
Flash und RAM.
Gerade für komplexe Projekte bietet C++ mehr, um den Code sauber zu 
strukturieren und zu dokumentieren. Vererbung kostet z.B. keine 
Ressourcen zur Laufzeit.

Schau doch mal hier vorbei:

http://roboterclubaachen.github.com/xpcc/
http://roboterclubaachen.github.com/xpcc/api/

Dort wird C++ für Mikrocontroller (AVR, ARM Cortex-M0 bis Cortex-M4, ARM 
7, AVR32, ...) benutzt.

Bei dem Beispiel

http://roboterclubaachen.github.com/xpcc/api/group__gpio.html

wird auch erläutert, wie das dann in Maschinencode aussieht.

Bewährt haben sich auf jeden Fall statische Methoden und Templates. Der 
Overhead durch vtables ist verschmerzbar, wenn man dadurch saubere, 
kompatible Interfaces hinbekommt.

LG

Dave

von Peter II (Gast)


Lesenswert?

Dave schrieb:
> Gerade für komplexe Projekte bietet C++ mehr, um den Code sauber zu
> strukturieren und zu dokumentieren.

schon merkwürdig das der ganze linux Kernel nur in C geschrieben ist, 
auch die leute dort noch den überblick behalten.

Man kann in C genauso sauber struktieren wie in C++. Das ist nur eine 
gewöhnungsfrage.

von temp (Gast)


Lesenswert?

Dave schrieb:
> Schau doch mal hier vorbei:
>
> http://roboterclubaachen.github.com/xpcc/
> http://roboterclubaachen.github.com/xpcc/api/

Das ist für mich ein klasse Negativbeispiel. Viel Aufwand für eine 
erlesen Auswahl an MCs. Und in meinen Augen unübersichtlich. Sowas würde 
ich mir nicht auf den Controller holen. Mag sein dass der Compiler 
daraus ordenlichen Code generiert. Das ist wieder wie mit jeder Lib. 
Wenn man alle Möglichkeiten der Perepherie bedenkt kriegt man einen 
riesen Klotz ans Bein gebunden. Wenn nur der kleinste gemeinsame Nenner 
drin ist, fehlt es überall und man fängt an dazu zu bauen. Wenn es dann 
ein neues Release der Lib gibt, geht's wieder von vorne los. Das ist 
aber unabhängig von C++. Irgendwie wiederholt sich der Schwachsinn, der 
in der PC-Programmierung zu beobachten ist, auf den Controllern. Das 
Ausnutzen der ganzen Möglichkeiten von C++ führt zu mehr 
unverständlichen Code als weniger. Klar ist es super einfach und 
verständlich ein "Led.Toggle()" zu benutzen. Wenn ich aber 5 Header- und 
Quellcode Dateien durchforsten muss um zu verstehen wie "Led" 
funktioniert, dann stimmt was nicht. Das Ziel der "Kapselug" sollte 
nicht in einem Versteckspiel enden. Das ist aber nur meine Meinung und 
andere sind ausdrücklich erlaubt.

von A. B. (funky)


Lesenswert?

PittyJ schrieb:
> Ich habe alles dynamische mit new/delete weggelassen. Dynamischer
> Speicher wollte ich in Interrupts nun doch nicht benutzen.
> Bei C hätte ich dann wohl auch malloc gespart.
>
> Den Rest von C++ habe ich benutzt.

So habe ich es auf einem STM32 auch gehalten. Dynamisch mache ich nix. 
Ist zwar manchmal ein wenig Speicherplatzverschwendung, aber ist 
aufgrund der Menge an Speicher überhaupt kein Problem

von Böserfisch (Gast)


Lesenswert?

Peter II schrieb:
> schon merkwürdig das der ganze linux Kernel nur in C geschrieben ist,
> auch die leute dort noch den überblick behalten.

Kernels sollte man aus Gründen der Stabilität und Einfachheit eigentlich 
immer in C (und ja, ohne Assembler geht's auch nicht) schreiben.
Bei Libraries gilt wieder: Nur C hat eine standardisierte und portable 
API. Bei OpenSource ist das bei C++ nicht so ein Thema, aber sobald es 
ums Einbinden fremder Libraries geht, kann man sich da tüchtig ins Knie 
schiessen.

Generell würde ich für stabile Software von C++ auf uCs ohne 
Betriebssystem eher absehen, einige 'bequeme' Features wie Exceptions 
und Allocator können recht tückisch sein und das Debugging schwierig 
machen. Dasselbe gilt aber auch für masslose Anwendung von C malloc().
Im Endeffekt halt eine Frage ob Hobby oder nötige Industrietauglichkeit. 
Im 'userspace' und für nicht kritische Tasks (GUI) ist C++ völlig ok, in 
einem sauberen Kernel wiederum ein no-go.

Das generelle Problem bei vielen C++-Programmen ist der oft zu 
akademische Ansatz, um auf Teufel-komm-raus objektorientierten Code zu 
schreiben. Oft lernen die Studenten schon gar kein C, geschweige denn 
Assembler mehr. Da geht das Keep-it-simple-Prinzip dann teils total 
verloren und artet nur noch in Coding-Onanie aus. Was das ganze auf den 
ersten Blick bei C++ einfacher macht, verleitet dann zu miesem 
Code-Design.

Die Nachteile von C++ überwiegen bei uC-Projekten (Portabilität, 
Platzbedarf) meiner Meinung nach. Wenn ich den Platz habe, haue ich 
lieber einen Python-Interpreter mit drauf und habe gleich eine 
vernünftige OO-Runtime-Umgebung mit Scripting.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.