Eine häufige Frage, hier und anderswo. Ist C ++ für eingebettete Systeme geeignet?
Mikrocontroller? RTOSes? Toaster? Embedded-PCs?
Ist OOP für Mikrocontroller nützlich?
Entfernt C ++ den Programmierer zu weit von der Hardware, um effizient zu sein?
Sollte Arduinos C ++ (ohne dynamische Speicherverwaltung, Vorlagen, Ausnahmen) als "echtes C ++" betrachtet werden?
(Hoffentlich wird dieses Wiki als Ort dienen, um diesen potenziellen heiligen Krieg einzudämmen.)
microcontroller
embedded
programming
c++
Toby Jaffey
quelle
quelle
Antworten:
Ja, C ++ ist in eingebetteten Systemen immer noch nützlich. Wie alle anderen gesagt haben, hängt es immer noch vom System selbst ab, wie ein 8-Bit-uC in meinem Buch wahrscheinlich ein Nein-Nein wäre, obwohl es einen Compiler gibt und einige Leute es tun (schaudern). Es ist immer noch ein Vorteil, C ++ zu verwenden, auch wenn Sie es auf etwas wie "C +" verkleinern, selbst in einer 8-Bit-Mikrowelt. Was meine ich mit "C +"? Ich meine, verwende nicht new / delete, vermeide Ausnahmen, vermeide virtuelle Klassen mit Vererbung, vermeide möglicherweise die Vererbung insgesamt, gehe sehr vorsichtig mit Vorlagen um, verwende Inline-Funktionen anstelle von Makros und verwende
const
Variablen anstelle von#defines
.Ich arbeite seit mehr als einem Jahrzehnt sowohl in C als auch in C ++ in eingebetteten Systemen, und ein Teil meiner jugendlichen Begeisterung für C ++ hat sich definitiv aufgrund einiger Probleme in der realen Welt gelegt, die die Naivität erschüttern. Ich habe das Schlimmste von C ++ in eingebetteten Systemen gesehen, die ich als "CS-Programmierer, die in einer EE-Welt verrückt geworden sind" bezeichnen möchte. Tatsächlich arbeite ich mit meinem Kunden daran, diese eine Codebasis zu verbessern, die sie unter anderem haben.
Die Gefahr von C ++ besteht darin, dass es ein sehr leistungsfähiges Werkzeug ist, das einem zweischneidigen Schwert ähnelt, das Ihnen sowohl den Arm als auch das Bein abschneiden kann, wenn es nicht in der Sprache und der allgemeinen Programmierung selbst geschult und diszipliniert ist. C ist eher ein einschneidiges Schwert, aber immer noch genauso scharf. Mit C ++ ist es zu einfach, sehr hohe Abstraktionsebenen zu erhalten und verschleierte Schnittstellen zu erstellen, die langfristig bedeutungslos werden. Dies liegt zum Teil an der Flexibilität von C ++ bei der Lösung desselben Problems mit vielen verschiedenen Sprachfunktionen (Vorlagen, OOP, prozedural, RTTI, OOP + -Vorlagen, Überladen, Inlining).
Ich beendete zwei 4-stündige Seminare über eingebettete Software in C ++ durch den C ++ - Guru Scott Meyers. Er wies auf einige Dinge über Vorlagen hin, die ich noch nie in Betracht gezogen hatte, und wie viel mehr sie beim Erstellen von sicherheitskritischem Code helfen können. Der Clou dabei ist, dass in Software kein toter Code enthalten sein darf, der strengen sicherheitskritischen Code-Anforderungen genügen muss. Vorlagen können Ihnen dabei helfen, da der Compiler nur den Code erstellt, den er zum Instanziieren von Vorlagen benötigt. Man muss sich jedoch gründlicher damit auskennen, um dieses Feature korrekt zu entwerfen, was in C schwieriger zu bewerkstelligen ist, da Linker nicht immer toten Code optimieren.
Scott Meyers ist ein sehr großer Befürworter von Vorlagen und einer vernünftigen Verwendung von Inlining, und ich muss sagen, dass ich immer noch skeptisch bin, wenn es um Vorlagen geht. Ich neige dazu, sie zu scheuen, obwohl er sagt, sie sollten nur dort angewendet werden, wo sie das beste Werkzeug sind. Er macht auch darauf aufmerksam, dass C ++ Ihnen die Werkzeuge zur Verfügung stellt, um wirklich gute Schnittstellen zu erstellen, die einfach zu verwenden sind und die es schwierig machen, falsch zu verwenden. Auch das ist der schwierige Teil. In C ++ muss eine gewisse Beherrschung erreicht werden, bevor Sie wissen, wie Sie diese Funktionen am effizientesten anwenden können, um die beste Entwurfslösung zu erhalten.
Gleiches gilt für OOP. In der eingebetteten Welt müssen Sie sich mit der Art des Codes vertraut machen, den der Compiler ausgibt, um zu wissen, ob Sie die Laufzeitkosten des Laufzeitpolymorphismus bewältigen können. Sie müssen auch bereit sein, Messungen durchzuführen, um zu beweisen, dass Ihr Design Ihre Terminanforderungen erfüllen wird. Wird diese neue InterruptManager-Klasse meine Interrupt-Latenz zu lang machen? Es gibt andere Formen des Polymorphismus, die möglicherweise besser zu Ihrem Problem passen, z. B. den Link-Time-Polymorphismus, den C ebenfalls kann, C ++ jedoch über das Pimpl-Entwurfsmuster (undurchsichtiger Zeiger). .
Ich sage das alles um zu sagen, dass C ++ seinen Platz in der Embedded-Welt hat. Sie können es hassen, was Sie wollen, aber es geht nicht weg. Es kann sehr effizient geschrieben werden, aber es ist schwieriger zu lernen, wie man es richtig macht als mit C. Es kann manchmal besser funktionieren als C, um ein Problem zu lösen und manchmal eine bessere Oberfläche auszudrücken, aber man muss es auch tun Erziehe dich selbst und habe keine Angst zu lernen, wie.
quelle
C ++ ist absolut geeignet für eingebettete Systeme. Ich benutze jetzt das Vorhandensein / Fehlen von guten Entwicklungswerkzeugen (oder das Fehlen von solchen) als mein primäres Kriterium dafür, ob ein bestimmter Mikroprozessor verwendet werden soll oder nicht.
Bereiche von C ++, die sich aufgrund ihrer geringen Ressourcenkosten gut für eingebettete Systeme eignen:
OK Bereiche:
Nicht zu verwendende Bereiche, vor allem aufgrund des auf kleinen Systemen nicht akzeptablen Laufzeitaufwands:
quelle
foo
Aufrufenbar
innerhalb einestry
/catch
-Blocks und beimbar
Erstellen einiger Objekte und Aufrufeboz
, die eine Ausnahme auslösen , das System die Destruktoren für diebar
erstellten Objekte irgendwie aufrufen muss, bevor die Steuerung an zurückgegeben wirdfoo
. Sofern Ausnahmen nicht vollständig deaktiviert sind,bar
haben Sie keine Möglichkeit zu wissen, obboz
sie ausgelöst werden könnten, und müssen daher zusätzlichen Code enthalten, um diese Möglichkeit zu ermöglichen. Ich würde gerne eine Variation von C ++ mit "geprüften Ausnahmen" sehen, um das zu lösen. Wenn Routinen, die Ausnahmen zu entkommen ermöglichen könnten ...add r15,r14,#2
beendenmov r15,r14
; über Ausnahme, zu verlassenldrhs r0,[r14] / add r15,r14,r0
. Keine Zykluskosten für den normalen Ausgang und keine Einschränkungen für Stapelrahmen.Ja, C ++ ist auf jeden Fall für eingebettete Systeme geeignet. Lassen Sie uns zunächst einige Missverständnisse über den Unterschied zwischen C und C ++ aufklären:
In einem eingebetteten Mikro müssen Sie immer sorgfältig Hochsprachen verwenden, wenn Sie Zeit- oder Raumbeschränkungen befürchten. Beispielsweise verarbeiten viele MCUs Zeiger nicht gut und sind daher bei der Verwendung des Stapels sehr ineffizient. Dies bedeutet, dass Sie vorsichtig sein müssen, wenn Sie Variablen mithilfe von Arrays und Zeigern und Rekursion an Funktionen übergeben. Eine einfache Zeile von C wie:
kann in Abhängigkeit von der Art dieser Variablen ungefähr 4 Seiten mit Anweisungen generieren.
Wenn Sie eine höhere Sprache verwenden und Zeit- und Raumprobleme haben, müssen Sie wissen, wie sich jede Funktion dieser Sprache in Maschinenanweisungen auf Ihrer MCU umsetzt (zumindest jede Funktion, die Sie verwenden). Dies gilt für C, C ++, Ada, was auch immer. Wahrscheinlich enthalten alle Sprachen Funktionen, die auf kleinen MCUs nicht effizient übersetzt werden können. Überprüfen Sie immer die Disassemblierungslisten, um sicherzustellen, dass der Compiler keine Unmengen von Anweisungen für etwas Triviales generiert.
Ist C für eingebettete MCUs geeignet? Ja, solange Sie den generierten Code im Auge behalten.
Ist C ++ für eingebettete MCUs geeignet? Ja, solange Sie den generierten Code im Auge behalten.
Hier ist der Grund, warum ich denke, dass C ++ sogar auf 8-Bit-MCUs besser ist als C: C ++ bietet verbesserte Unterstützung für:
Keines dieser Merkmale ist schwerer als die typischen Merkmale von C.
Wenn Sie bis zu 16- oder 32-Bit-MCUs verschieben, ist es sinnvoll, die umfangreicheren Funktionen von C (Stapel, Heap, Zeiger, Arrays, PrintF usw.) zu verwenden. Auf die gleiche Weise eignet sich eine leistungsstärkere MCU schwerere Funktionen von C ++ zu verwenden (Stack, Heap, Referenzen, AWL, neu / löschen).
Der Gedanke an C ++ auf einem PIC16 muss also nicht erschaudern. Wenn Sie Ihre Sprache und Ihre MCU richtig kennen, wissen Sie, wie Sie beide effektiv zusammen einsetzen können.
quelle
a[i] = b[j] * c[k];
Kann in Abhängigkeit von der Art dieser Variablen ungefähr 4 Seiten mit Anweisungen erzeugen." Wenn Ihr MCU / Compiler dies tut, liegt es daran, dass Sie eine Werkstatt-Hobby-CPU aus den 80ern verwenden.Ich finde diese Debatten immer unterhaltsam zu lesen. Nicht so sehr für die intellektuelle Diskussion über die Vor- und Nachteile der verschiedenen verfügbaren Sprachen, sondern weil Sie normalerweise die Einstellung eines Menschen zum Thema auf der Grundlage seines Jobs / seiner Erfahrung / seines Interessengebiets festlegen können. Es stimmt mit den Argumenten der "vorzeitigen Optimierung" überein, dass die CS-Majors und Wartungsprogrammierer Knuth links und rechts zitieren, und diejenigen, die in der realen Welt arbeiten, in der es auf die Leistung ankommt, denken, sie seien alle verrückt (ich bin ein Mitglied der letzteren Gruppe) um fair zu sein).
Letztendlich können Sie hier exzellente Software in C oder C ++ entwickeln oder Sprache einfügen . Es kommt auf die Fähigkeiten des Entwicklers an, nicht auf die Sprache. Ein Experte in einer Sprache zu sein, ist normalerweise nur dann erforderlich, wenn Sie die falsche Sprache ausgewählt haben und diese nun zur Lösung Ihres Problems verwenden müssen. In den meisten Fällen sind dies die einzigen Situationen, in denen Sie sich mit undurchsichtigen Funktionen oder Compilern auseinandersetzen müssen Tricks, um das Ziel zu erreichen.
Ich höre oft Leute, die diese Argumente als "Ich bin ein Experte in Sprache X und bla bla" anfangen. Ich diskreditiere diese Leute ehrlich gesagt sofort, weil sie meiner Meinung nach das Problem bereits aus dem falschen Blickwinkel angegangen sind und alles danach verdorben ist durch ihren Wunsch, mit ihrem Werkzeug das Problem zu lösen und zu zeigen, wie 'cool' es ist.
Ich beobachte so oft, wie Entwickler zuerst ein Tool-Set auswählen und dann versuchen, es an ihr Problem anzupassen, was völlig falsch ist und zu Mistlösungen führt.
Wie ich in einem Kommentar zu einer anderen Antwort erwähnt habe, wird in diesen Sprachkriegen oft argumentiert, dass die Sprache X dem Programmierer erlaubt, mehr dumme Dinge zu tun. Während das Lesen unterhaltsam ist, bedeuten all diese Aussagen, dass Sie ein Problem damit haben, gute Entwickler einzustellen und dieses Problem direkt angehen müssen, anstatt zu versuchen, die Situation zu verbessern, indem Sie weiterhin schlechte Entwickler einstellen und Tools auswählen, die so wenig wie möglich leisten Schaden wie möglich.
Meiner Meinung nach sind gute Entwickler, sei es Software- oder Hardware-Entwicklung, recherchieren das Problem, entwickeln eine Lösung und finden die Werkzeuge, mit denen sie die Lösung auf die "beste Art und Weise" ausdrücken können. Es sollte keine Rolle spielen, ob das benötigte Tool etwas ist, das Sie noch nie zuvor verwendet haben. Nachdem Sie 3-4 Sprachen / Entwicklungstools für Projekte verwendet haben, die ein neues Tool aufnehmen, sollte dies nur minimale Auswirkungen auf Ihre Entwicklungszeit haben.
Natürlich ist 'bester Weg' ein subjektiver Begriff und muss auch in der Forschungsphase definiert werden. Man muss eine Vielzahl von Aspekten berücksichtigen: Leistung, einfache Ausdrucksweise, Codedichte usw., basierend auf dem vorliegenden Problem. Ich habe die Wartbarkeit aus einem bestimmten Grund nicht in diese Liste aufgenommen. Es ist mir egal, welche Sprache Sie auswählen, wenn Sie das richtige Tool ausgewählt und sich die Zeit genommen haben, um das Problem zu verstehen, das "kostenlos" auftreten sollte. Schwierig zu pflegender Code ist oft das Ergebnis der Wahl des falschen Tools oder einer schlechten Systemstruktur. Dies führt zu einem hässlichen Durcheinander, damit es funktioniert.
Die Behauptung, dass eine Sprache besser ist als jede andere, ist dumm, ohne ein bestimmtes Problem von Interesse zu definieren. Ein objektorientierter Ansatz ist nicht immer besser als ein funktionaler Ansatz. Es gibt einige Probleme, die sich sehr gut für ein objektorientiertes Designparadigma eignen. Es gibt viele, die dies nicht tun. Dieselbe Aussage kann über viele Sprachmerkmale gemacht werden, auf denen die Leute gerne zu harpen scheinen.
Wenn Sie mehr als 20% Ihrer Zeit mit dem eigentlichen Eingeben von Code verbringen, produzieren Sie wahrscheinlich ein sehr schlechtes System oder haben sehr schlechte Entwickler (oder Sie lernen noch). Sie sollten die meiste Zeit im Voraus damit verbringen, das Problem zu beschreiben und zu bestimmen, wie die verschiedenen Teile der Anwendung interagieren. Wenn Sie eine Gruppe talentierter Entwickler in einen Raum mit einem Markierungsfeld und einem zu lösenden Problem stecken und ihnen mitteilen, dass sie keinen Code schreiben oder Werkzeuge auswählen dürfen, bis sie sich mit dem gesamten System vertraut fühlen, wird dies die Qualität des verbessern Leistung und Geschwindigkeit der Entwicklung als bei der Auswahl eines neuen Tools, das die Entwicklungszeit garantiert verkürzt. (Scrum Development als Referenz für das Gegenteil meiner Argumentation nachschlagen)
Leider können viele Unternehmen den Wert eines Entwicklers nur anhand der Anzahl der geschriebenen Zeilen oder anhand der "greifbaren Ausgabe" messen. Sie betrachten die 3 Wochen in einem Raum mit einer Markierungstafel als Produktivitätsverlust. Entwickler sind oft gezwungen, die "Gedanken" -Entwicklungsphase zu durchlaufen, oder sind gezwungen, ein Tool zu verwenden, das durch ein politisches Problem innerhalb des Unternehmens festgelegt wurde: "Der Bruder meines Chefs arbeitet für IBM, damit wir nur ihre Tools verwenden können." . Oder schlimmer noch, Sie bekommen ständig wechselnde Anforderungen vom Unternehmen, weil sie keine ordnungsgemäße Marktforschung durchführen können oder die Auswirkungen von Änderungen auf den Entwicklungszyklus nicht verstehen.
Es tut mir leid, dass ich mit diesem Geschwätz ein wenig vom Thema abkam. Ich habe ziemlich starke Meinungen zu diesem Thema.
quelle
Jede Sprache kann für ein eingebettetes System geeignet sein. Eingebettet heißt nur: Teil eines größeren Geräts im Gegensatz zu einem frei verwendbaren Computer.
Die Frage ist relevanter, wenn nach einem (harten) Echtzeitsystem oder einem System mit begrenzten Ressourcen gefragt wird.
Für ein Echtzeitsystem ist C ++ eine der höchsten Sprachen, die beim Programmieren unter Berücksichtigung strenger Zeitbeschränkungen immer noch angemessen ist. Mit Ausnahme der Verwendung von Heap (freier Operator) gibt es keine Konstrukte mit einer unbestimmten Ausführungszeit. Sie können also testen, ob Ihr Programm die Timing-Anforderungen erfüllt, und mit etwas mehr Erfahrung können Sie es sogar vorhersagen. Die Verwendung von Heap sollte natürlich vermieden werden, obwohl der neue Operator weiterhin für die einmalige Zuweisung verwendet werden kann. Die Konstrukte, die C ++ über C anbietet, können in einem eingebetteten System sinnvoll eingesetzt werden: OO, Ausnahmen, Vorlagen.
Für sehr ressourcenbeschränkte Systeme (8-Bit-Chips, weniger als ein paar KB RAM, kein verfügbarer Stapel) ist volles C ++ möglicherweise ungeeignet, obwohl es immer noch als "besseres C" verwendet werden kann.
Ich finde es bedauerlich, dass Ada nur in einigen Nischen eingesetzt zu werden scheint. In vielerlei Hinsicht ist es ein Pascal ++, aber ohne die Last, mit einer Sprache aufwärtskompatibel zu sein, die anfangs schon ein ernstes Durcheinander war. (redigieren Sie: das ernste Durcheinander ist natürlich C. Pascal ist eine schöne, aber etwas unpraktische Sprache.)
================================================ ==============
BEARBEITEN: Ich habe eine Antwort auf eine neue Frage eingegeben ("In welchen Fällen ist C ++ erforderlich, wenn wir Mikrocontroller programmieren?"), Die unter Bezugnahme auf diese geschlossen wurde. Deshalb werde ich hinzufügen, was ich geschrieben habe:
Es gibt nie einen ausschlaggebenden Grund für die Verwendung einer Programmiersprache, aber es kann Argumente geben, die in einer bestimmten Situation mehr oder weniger Gewicht haben. Diskussionen darüber finden sich an vielen Stellen, mit Positionen, die von "Verwenden Sie niemals C ++ für einen Mikrocontroller" bis "Verwenden Sie immer C ++" reichen. Ich bin mehr mit der letzten Position. Ich kann einige Argumente anführen, aber Sie müssen selbst entscheiden, wie viel Gewicht sie in einer bestimmten Situation (und in welche Richtung) haben.
Mein Blog enthält einige Schriften zur Verwendung von C ++ auf kleinen Systemen (= Mikrocontrollern).
quelle
Nach meiner Erfahrung eignet sich C ++ normalerweise nicht für kleine eingebettete Systeme. Damit meine ich Mikrocontroller und Geräte ohne Betriebssystem.
Viele C ++ - OOP-Techniken basieren auf der dynamischen Speicherzuweisung. Dies fehlt häufig in kleinen Systemen.
STL und Boost demonstrieren die Leistungsfähigkeit von C ++, beide haben eine enorme Stellfläche.
C ++ ermutigt den Programmierer, die Maschine zu abstrahieren, wo sie in eingeschränkten Systemen berücksichtigt werden muss.
Letztes Jahr habe ich ein kommerzielles Remote-Desktop-Produkt auf Mobiltelefone portiert. Es wurde in C ++ geschrieben und lief unter Windows, Linux und OSX. Es stützte sich jedoch stark auf STL, dynamischen Speicher und C ++ - Ausnahmen. Um es in WinCE-, Symbian- und OS-freien Umgebungen zum Laufen zu bringen, war ein C-Rewrite die vernünftigste Option.
quelle
Ich hoffe, diese Diskussion über C ++ auf Bare-Metal- und ressourcenbeschränkten Systemen mit mehr Licht als Wärme zu füllen.
Probleme in C ++:
Ausnahmen sind insbesondere ein RAM-Problem, da der erforderliche "Notfallpuffer" (bei dem beispielsweise die Ausnahme "Nicht genügend Arbeitsspeicher" auftritt) größer sein kann als der verfügbare RAM und sicherlich eine Verschwendung für Mikrocontroller darstellt. Weitere Informationen finden Sie unter n4049 und n4234 . Sie sollten ausgeschaltet sein (was derzeit kein bestimmtes Verhalten ist, also seien Sie sicher und werfen Sie niemals). SG14 arbeitet derzeit an besseren Wegen, dies zu tun.
RTTI ist wahrscheinlich nie den Aufwand wert, es sollte ausgeschaltet sein
Große Debug-Builds, obwohl dies in der klassischen Desktop-Entwicklung kein Problem darstellt. Wenn das Debug nicht auf den Chip passt, kann es ein Problem sein. Das Problem entsteht durch Vorlagencode oder zusätzliche Funktionsaufrufe, die der Übersichtlichkeit halber hinzugefügt wurden. Diese zusätzlichen Funktionsaufrufe werden vom Optimierer wieder entfernt und die zusätzliche Klarheit oder Flexibilität kann ein großer Vorteil sein. Bei Debug-Builds kann dies jedoch ein Problem sein.
Heap-Zuordnung. Obwohl die AWL die Verwendung von benutzerdefinierten Zuweisern zulässt, kann dies für die meisten Programmierer komplex sein. Die Heap-Zuweisung ist nicht deterministisch (dh keine harte Echtzeit) und Fragmentierung kann zu unerwarteten Situationen außerhalb des Arbeitsspeichers führen, die auftreten können, obwohl sie beim Testen gearbeitet haben. Die Buchhaltung, die der Haufen benötigt, um den freien Speicherplatz und die unterschiedliche Größe im Auge zu behalten, kann bei kleinen Objekten ein Problem sein. Normalerweise ist es besser, die Poolzuordnung zu verwenden (sowohl in C als auch in C ++), aber dies kann für C ++ - Programmierer, die nur den Heap verwenden, ungewöhnlich sein.
Laufzeit-Polymorphismus und andere indirekte Aufrufe sind in der Regel ein großer Leistungseinbruch. Das Problem liegt in der Regel darin, dass der Optimierer sie nicht mehr durchschauen kann als das eigentliche Abrufen und Springen zur Adresse. Indirekte Aufrufe sind aus diesem Grund in C und C ++ zu vermeiden, wo sie wie in C ++ stärker in der Kultur verankert sind (und in anderen Bereichen durchaus nützlich sind).
Eine implizite Verbindung mit clib kann problematisch sein. Es mag unerklärlich sein, dass Clib-Probleme in der Kategorie C ++ liegen, aber das Problem ergibt sich aus der impliziten gemeinsamen Nutzung von Ressourcen in gleichzeitigen Umgebungen (die gemeinsame Nutzung ist in C expliziter). Die Verwendung der allgemeinen newLib-Implementierung führt häufig zu viel Aufblähung, die in der Regel in uCs nicht benötigt wird. Andererseits ist newLibNanno nicht wiedereintrittsfähig, sodass der Zugriff darauf serialisiert werden muss (hier zu stark vereinfacht). Dies ist auch für C ein Problem, aber der Zugriff ist expliziter. Als Faustregel sollte man im ISR-Kontext im Wesentlichen nichts aus dem Namespace std verwenden, es sei denn, Sie sind sicher, dass es nicht irgendwie auf den Status in clib zugreift (z. B. errorno oder der Heap). Es ist auch wichtig, wenn Sie Threads verwenden (ich bevorzuge RTC), um new zu überschreiben und delete, um den Zugriff auf malloc und free zu synchronisieren.
Zusammenfassend lässt sich sagen, dass C ++ einige Probleme aufweist, die jedoch im Wesentlichen alle behoben oder vermieden werden können.
Jetzt für C, hier ist das Problem höherer Ordnung. Ich habe nicht die syntaktische Fähigkeit in C, Dinge so zu abstrahieren, dass ich beim Kompilieren Optimierungen durchführen oder Invarianten überprüfen kann. Daher kann ich Dinge nicht richtig kapseln, sodass der Benutzer nicht wissen muss, wie sie funktionieren, um sie zu verwenden, und der größte Teil meiner Fehlererkennung erfolgt zur Laufzeit (was nicht nur zu spät ist, sondern auch zusätzliche Kosten verursacht). Grundsätzlich ist die einzige Möglichkeit, in C generisch zu sein, Daten zu verwenden. Ich übergebe einen Format-String an printf oder scanf, der beispielsweise zur Laufzeit ausgewertet wird. Für den Compiler ist es dann ziemlich schwierig zu beweisen, dass ich einige der Optionen nicht verwende, die theoretisch möglich sind, wenn die richtigen Daten übergeben werden, was potenzielle Generierung von totem Code und Verlust von Optimierungspotential bedeutet.
Ich weiß, dass ich hier vielleicht einen Scheiß auslöse, aber meine Erfahrung mit 32-Bit-Mikrocontrollern ist, dass in einem Apfel-zu-Apfel-Vergleich von C und C ++, die beide von Experten geschrieben wurden (wie in C ++, das möglicherweise stark von Templaten betroffen ist), C ++ die effizientere Sprache ist, sobald Alles muss generisch sein (wie in jeder Bibliothek) und in nicht generischen Fällen sind sie im Wesentlichen gleichwertig. Es ist für Anfänger auch einfacher, das Fachwissen eines Experten für die Implementierung von Bibliotheken in C ++ zu nutzen.
Gleichzeitig gibt es tatsächlich wirklich wenige Funktionen, an die ich keine falschen Daten übergeben kann, sobald die Eingabe kein int ist,
something
für die ich aber zufällig ein int als Darstellungsmethode verwende, besteht die Möglichkeit, dass ich sie bekomme falsch (übergebe einen ungültigen Wert oder ein 'otherThing' anstatt eines 'something'). In C kann ich nur zur Laufzeit prüfen, ob der Benutzer etwas falsch gemacht hat. In C ++ habe ich die Möglichkeit, einige Überprüfungen durchzuführen, nicht alle Überprüfungen, sondern einige Überprüfungen zur Kompilierungszeit, die frei sind.Am Ende des Tages ist ein C-Team oft so mächtig wie sein schwächster Programmierer, und der Vorteil des resultierenden Codes besteht entweder in einem 1er-Multiplayer oder in einer Leistungsstrafe. Was ich damit meine, ist, dass es entweder eine hohe Leistung für einen und nur einen einzigen Auftrag in einer einzigartigen Umgebung mit einzigartigen Entwurfsentscheidungen bietet oder generisch genug ist, um in mehreren Umgebungen verwendet zu werden (anderer Mikrocontroller, andere Speichermanagementstrategie, andere Latenz vs. Durchsatzkompromisse usw. usw.), hat jedoch inhärente Leistungskosten.
In C ++ können Dinge von Experten gekapselt und in vielen Umgebungen verwendet werden, in denen sich die Generierung von Kompilierungs-Zeitcode an die jeweilige Aufgabe anpasst und die statische Überprüfung Benutzer davon abhält, dumme Dinge zu Nullkosten zu erledigen. Hier haben wir einen weitaus geringeren Kompromiss zwischen allgemeinem und schnellem Sprachgebrauch. Letztendlich ist die Sprache unter Kosten-Nutzen-Gesichtspunkten performanter, sicherer und produktiver.
Es ist eine berechtigte Kritik, dass es immer noch einen großen Mangel an guten C ++ - Bibliotheken für Embedded gibt. Dies kann zu pragmatischen Entscheidungen führen, hauptsächlich C auf einem C ++ - Compiler zu verwenden. Die Entscheidung, in einem Projekt nur C zu verwenden, ist im Wesentlichen entweder ideologisch motiviert, aus Gründen der Legacy-Unterstützung oder dem Eingeständnis, dass das Team nicht diszipliniert genug ist, um von einer Reihe sehr ausgewählter dummer Dinge Abstand zu nehmen, die man in C ++, aber nicht in C tun kann und gleichzeitig diszipliniert genug, um keine der weitaus größeren dummen Dinge zu tun, gegen die man sich in C nicht schützen kann, aber in C ++ könnte.
quelle
Mein Hintergrund: gerade nach der Schulausbildung bei alten Bell Labs-Programmierern; Ich arbeite seit 3 Jahren, 2 an einem Undergrad-Forschungsprojekt. Datenerfassung / Prozesskontrolle in VB.NET. Verbrachte 1,5 Jahre mit der Arbeit an einer Unternehmensdatenbankanwendung in VB6. Derzeit wird an einem Projekt für einen Embedded- PC mit 2 GB Speicher, 512 MB RAM und 500 MHz x 86-CPU gearbeitet. Mehrere Apps, die gleichzeitig in C ++ mit einem dazwischen liegenden IPC-Mechanismus ausgeführt werden. Ja ich bin jung
Meine Meinung: Ich denke, C ++ kann in der oben beschriebenen Umgebung effektiv arbeiten . Zugegebenermaßen ist eine harte Echtzeitleistung keine Voraussetzung für die App, auf der ich arbeite, und in einigen eingebetteten Anwendungen kann dies ein Problem sein. Aber hier sind die Dinge, die ich gelernt habe:
C ++ unterscheidet sich grundlegend von C (dh es gibt kein C / C ++). Während alles, was für C gültig ist, für C ++ gilt, ist C ++ eine ganz andere Sprache und man muss lernen, wie man in C ++ programmiert und nicht in C, um es in jeder Situation effektiv zu nutzen . In C ++ müssen Sie objektorientiert programmieren, nicht prozedural und nicht hybrid (große Klassen mit vielen Funktionen). Im Allgemeinen sollten Sie sich darauf konzentrieren, kleine Klassen mit wenigen Funktionen zu erstellen und alle kleinen Klassen zusammen zu einer größeren Lösung zusammenzufassen. Einer meiner Kollegen erklärte mir, dass ich früher prozedural in Objekten programmiert habe, was ein großes Durcheinander ist und schwer zu pflegen ist. Als ich anfing, objektorientiertere Techniken anzuwenden, stellte ich fest, dass die Wartbarkeit / Lesbarkeit meines Codes verbessert wurde.
C ++ bietet zusätzliche Funktionen in Form einer objektorientierten Entwicklung, mit denen sich Code vereinfachen und leichter lesen und pflegen lässt . Ehrlich gesagt glaube ich nicht, dass eine Verbesserung der Leistung / Raumeffizienz beim Ausführen von OOP viel im Wege steht. Aber ich denke, OOP ist eine Technik, die helfen kann, ein komplexes Problem in viele kleine Teile aufzuteilen. Und das ist hilfreich für die Leute, die am Code arbeiten, ein Element dieses Prozesses, das nicht ignoriert werden sollte.
Viele Argumente gegen C ++ haben in erster Linie mit der dynamischen Speicherzuweisung zu tun. C hat das gleiche Problem auch. Sie können eine objektorientierte Anwendung schreiben, ohne dynamischen Speicher zu verwenden. Einer der Vorteile der Verwendung von Objekten besteht jedoch darin, dass Sie diese Dinge auf einfache Weise dynamisch zuordnen können. Genau wie in C müssen Sie vorsichtig sein, wie die Daten verwaltet werden, um Speicherverluste zu reduzieren. Die RAII-Technik vereinfacht dies jedoch in C ++ (dynamische Speicherzerstörung wird automatisch durch Kapselung in Objekte durchgeführt). In einigen Anwendungen, in denen jeder Speicherort zählt, ist dies möglicherweise zu wild und zu wollig, um verwaltet zu werden.
BEARBEITEN:
quelle
Ja, das Problem mit C ++ ist der größere Platzbedarf des Codes.
In einigen Systemen zählen Sie Bytes, und in diesem Fall müssen Sie die Betriebskosten in Kauf nehmen, die so hoch sind, dass die Entwicklungskosten für C nahe an den Grenzen Ihrer Systeme liegen.
Aber selbst in C müssen Sie für ein gut gestaltetes System alles gekapselt lassen. Gut konzipierte Systeme sind schwierig, und C ++ bietet Programmierern einen Platz für eine sehr strukturierte und kontrollierte Entwicklungsmethode. Das Erlernen von OOP ist mit Kosten verbunden, und wenn Sie darauf wechseln möchten, akzeptieren Sie dies sehr. In vielen Fällen würde das Management lieber mit C fortfahren und die Kosten nicht bezahlen, da es schwierig ist, die Ergebnisse eines solchen Wechsels zu messen erhöht die Produktivität. Einen Artikel des Embedded-Systems-Gurus Jack Ganssle finden Sie hier .
Dynamische Speicherverwaltung ist der Teufel. Nicht wirklich, der Teufel ist die automatische Weiterleitung. Dynamische Speicherverwaltung funktioniert auf einem PC hervorragend, aber Sie können davon ausgehen, dass Sie mindestens alle paar Wochen einen PC neu starten. Sie werden feststellen, dass ein eingebettetes System, das 5 Jahre lang weiterarbeitet, die dynamische Speicherverwaltung stark beeinträchtigen kann und tatsächlich ausfällt. Ganssle beschreibt Dinge wie Stapel und Haufen in seinem Artikel.
Es gibt einige Dinge in C ++, die eher zu Problemen führen und viele Ressourcen verbrauchen. Das Entfernen der dynamischen Speicherverwaltung und der Vorlagen sind große Schritte, um den Footprint von C ++ näher an den Footprint von C heranzuführen. Dies ist immer noch C ++, Sie benötigen kein dynamisches Format Speicherverwaltung oder Vorlagen, um gutes C ++ zu schreiben. Ich habe nicht bemerkt, dass sie Ausnahmen entfernt haben. Ich betrachte Ausnahmen als einen wichtigen Teil meines Codes, den ich in der Veröffentlichung entferne, aber bis dahin verwende. Beim Feldtest können Ausnahmen Meldungen generieren, um mich über das Auftreten einer Ausnahme zu informieren.
quelle
Ich fand diesen Anti-C ++ - Rant von Linus Torvalds interessant.
Er spricht nicht von der Welt der eingebetteten Systeme, sondern von der Entwicklung des Linux-Kernels. Für mich ergibt sich die Relevanz daraus: C ++ erfordert das Verständnis eines größeren Kontexts, und ich kann lernen, eine Reihe von Objektvorlagen zu verwenden. Ich traue mich nicht, mich an sie zu erinnern, wenn ich den Code in einigen Monaten aktualisieren muss.
(Andererseits arbeite ich derzeit an einem eingebetteten Gerät mit Python (nicht C ++, aber mit demselben OOP-Paradigma), das genau dieses Problem hat. Zu meiner Verteidigung ist es ein eingebettetes System, das leistungsfähig genug ist, um als PC bezeichnet zu werden.) vor 10 Jahren.)
quelle
Ich denke, andere Antworten haben die Vor- und Nachteile sowie die Entscheidungsfaktoren ziemlich gut dargelegt, daher möchte ich nur ein paar Kommentare zusammenfassen und hinzufügen.
Für kleine Mikrocontroller (8-Bit) auf keinen Fall. Sie bitten nur, sich selbst zu verletzen, es gibt keinen Gewinn und Sie geben zu viele Ressourcen auf.
Für High-End-Mikrocontroller (z. B. 32-Bit, 10 oder 100 MB für RAM und Speicher) mit einem anständigen Betriebssystem ist dies vollkommen in Ordnung und kann sogar empfohlen werden.
Die Frage ist also: Wo ist die Grenze?
Ich weiß es nicht genau, aber ich habe einmal ein 16-Bit-uC-System mit 1 MB RAM und 1 MB Speicher in C ++ entwickelt, um es später zu bereuen. Ja, es hat funktioniert, aber die zusätzliche Arbeit, die ich hatte, war es nicht wert. Ich musste es fit machen, sicherstellen, dass Dinge wie Ausnahmen keine Lecks produzieren (die Unterstützung von OS + RTL war ziemlich fehlerhaft und unzuverlässig). Darüber hinaus führt eine OO-App in der Regel viele kleine Zuweisungen durch, und der Mehraufwand für diese war ein weiterer Albtraum.
Aufgrund dieser Erfahrung würde ich für zukünftige Projekte davon ausgehen, dass ich C ++ nur in Systemen mit mindestens 16 Bit und mit mindestens 16 MB RAM und Speicher wählen werde. Dies ist eine willkürliche Grenze und hängt wahrscheinlich von der Art der Anwendung, den Codierungsstilen und Redewendungen usw. ab. Angesichts der Einschränkungen würde ich einen ähnlichen Ansatz empfehlen.
quelle
Es gibt einige Funktionen von C ++, die in eingebetteten Systemen nützlich sind. Es gibt andere, wie zum Beispiel Ausnahmen, die teuer sein können und deren Kosten nicht immer offensichtlich sind.
Wenn ich meine Druthers hätte, würde es eine populäre Sprache geben, die das Beste aus beiden Welten kombiniert und einige Merkmale enthält, die in beiden Sprachen fehlen. Einige Anbieter bieten einige dieser Funktionen an, es gibt jedoch keine Standards. Ein paar Dinge, die ich gerne sehen würde:
Ich weiß, der Vater von C ++ ist nicht besonders an einer Embedded-Only-Version von C ++ interessiert, aber ich würde denken, dass es einige erhebliche Verbesserungen gegenüber der Verwendung von C bieten könnte.
Weiß jemand, ob so etwas für irgendeine Art von Norm in Betracht gezogen wird?
quelle
C ++ ist mehr als eine Programmiersprache:
a) Es ist eine "bessere" C b) Es ist eine objektorientierte Sprache c) Es ist eine Sprache, mit der wir generische Programme schreiben können
Obwohl alle diese Funktionen separat verwendet werden können, werden die besten Ergebnisse erzielt, wenn die drei Funktionen gleichzeitig verwendet werden. Wenn Sie jedoch nur eine davon auswählen, erhöht sich die Qualität der eingebetteten Software.
a) Es ist ein "besseres" C
C ++ ist eine stark typisierte Sprache. stärker als C. Ihre Programme werden von dieser Funktion profitieren.
Einige Leute haben Angst vor Zeigern. C ++ enthält die Referenzen. Überladene Funktionen.
Und es lohnt sich zu erwähnen: Keine dieser Funktionen tritt in größeren oder langsameren Programmen auf.
b) Es ist eine objektorientierte Sprache
Jemand sagte in diesem Beitrag, dass es keine gute Idee ist, die Maschine in Mikrocontrollern zu abstrahieren. Falsch! Wir alle, die Embedded-Ingenieure, haben die Maschine immer abstrahiert, nur mit einer anderen Steuer als der von C ++. Das Problem, das ich mit diesem Argument sehe, ist, dass einige Programmierer nicht daran gewöhnt sind, in Objekten zu denken. Auf diese Weise sehen sie die Vorteile von OOP nicht.
Wann immer Sie bereit sind, das Peripheriegerät eines Mikrocontrollers zu verwenden, ist es wahrscheinlich, dass das Peripheriegerät in Form des Gerätetreibers für uns (von Ihnen selbst oder von Dritten) abstrahiert wurde. Wie ich bereits sagte, verwendet dieser Treiber die C-Sintax, wie das folgende Beispiel zeigt (direkt aus einem NXP-LPC1114-Beispiel entnommen):
/ * Timer-Setup für Match und Interrupt bei TICKRATE_HZ * /
Chip_TIMER_Reset (LPC_TIMER32_0);
Chip_TIMER_MatchEnableInt (LPC_TIMER32_0, 1);
Chip_TIMER_SetMatch (LPC_TIMER32_0, 1, (timerFreq / TICKRATE_HZ2));
Chip_TIMER_ResetOnMatchEnable (LPC_TIMER32_0, 1);
Chip_TIMER_Enable (LPC_TIMER32_0);
Sehen Sie die Abstraktion? Wenn Sie also C ++ für den gleichen Zweck verwenden, wird die Abstraktion durch den Abstraktions- und Kapselungsmechanismus von C ++ auf die nächste Ebene gebracht, und zwar zu Nullkosten!
c) Es ist eine Sprache, mit der wir generische Programme schreiben können
Generische Programme werden über Vorlagen erstellt, und Vorlagen sind für unsere Programme ebenfalls kostenlos.
Außerdem wird mit Vorlagen ein statischer Polymorphismus erzielt.
Virtuelle Methoden, RTTI und Ausnahmen.
Bei der Verwendung virtueller Methoden gibt es einen Kompromiss: Bessere Software vs. Leistungseinbußen. Beachten Sie jedoch, dass die dynamische Bindung wahrscheinlich mithilfe einer virtuellen Tabelle (einem Array von Funktionszeigern) implementiert wird. Ich habe dasselbe in C oft gemacht (auch regelmäßig), so dass ich die Nachteile der Verwendung virtueller Methoden nicht sehe. Darüber hinaus sind virtuelle Methoden in C ++ eleganter.
Abschließend ein Hinweis zu RTTI und Ausnahmen: VERWENDEN SIE SIE NICHT in eingebetteten Systemen. Vermeiden Sie sie um jeden Preis!
quelle
Mein Hintergrund, eingebettet (mcu, pc, unix, andere), Echtzeit. Sicherheitskritisch. Ich habe einen früheren Arbeitgeber bei STL vorgestellt. Das mache ich nicht mehr
Einige Flammeninhalte
Ist C ++ für eingebettete Systeme geeignet?
Meh. C ++ ist ein Schmerz zu schreiben und ein Schmerz zu pflegen. C + ist in Ordnung (benutze einige Funktionen nicht)
C ++ in Mikrocontrollern? RTOSes? Toaster? Embedded-PCs?
Wieder sage ich Meh. C + ist nicht schlecht, aber ADA ist weniger schmerzhaft (und das sagt wirklich etwas aus). Wenn du Glück hast wie ich, kannst du Embedded Java machen. Ein überprüfter Array-Zugriff und keine Zeigerarithmetik ergeben einen sehr zuverlässigen Code. Garbage Collectors in eingebettetem Java haben nicht die höchste Priorität, und die Wiederverwendung von Speicher und Objekten ist begrenzt, sodass gut gestalteter Code ohne GC für immer ausgeführt werden kann.
Ist OOP für Mikrocontroller nützlich?
Sicher ist. Der UART ist ein Objekt ..... Der DMAC ist ein Objekt ...
Objektzustandsautomaten sind sehr einfach.
Entfernt C ++ den Programmierer zu weit von der Hardware, um effizient zu sein?
Wenn es sich nicht um einen PDP-11 handelt, ist C nicht Ihre CPU. C ++ war ursprünglich ein Präprozessor auf C, sodass Bjarne Stroustrup nicht mehr darüber belacht wurde, dass er bei AT & T langsame Simula-Simulationen hatte. C ++ ist nicht Ihre CPU.
Holen Sie sich eine MCU, die Java-Bytecodes ausführt. Programm in Java. Lache über die C Jungs.
Sollte Arduinos C ++ (ohne dynamische Speicherverwaltung, Vorlagen, Ausnahmen) als "echtes C ++" betrachtet werden?
Nee. Genau wie alle bastardisierten C-Compiler für MCUs.
Forth, Embedded Java oder Embedded ADA sind standardisiert (ish); Alles andere ist Trauer.
quelle
Eingebettete Systeme sind so konzipiert, dass sie eine bestimmte Aufgabe erfüllen und nicht als Universalcomputer für mehrere Aufgaben dienen. Ein eingebettetes System ist eine Kombination aus Computerhardware und -software. C ist die Mutter aller modernen Sprachen. Es handelt sich um eine Sprache mit niedrigem Sprachniveau und voller Leistung, die sich mit allen Arten von Hardware befasst. Daher ist C / C ++ eine optimale Wahl für die Entwicklung von Software für eingebettete Systeme, die für jedes eingebettete System sehr nützlich ist. Wie wir wissen, ist C eine Entwicklungssprache. Das Betriebssystem UNIX ist in C geschrieben. Da bei einer erfolgreichen Softwareentwicklung häufig die beste Sprache für ein bestimmtes Projekt ausgewählt wird, ist es überraschend, dass sich die C / C ++ - Sprache sowohl für 8-Bit- als auch für 64-Bit-Prozessoren als geeignet erwiesen hat ; in Systemen mit Byte, Kilobyte und Megabyte Arbeitsspeicher. C hat den Vorteil der Prozessorunabhängigkeit, Dadurch können sich Programmierer auf Algorithmen und Anwendungen konzentrieren und nicht auf die Details einer bestimmten Prozessorarchitektur. Viele dieser Vorteile gelten jedoch auch für andere Hochsprachen. Aber C / C ++ war erfolgreich, wo so viele andere Sprachen größtenteils gescheitert sind?
quelle
<rant>
Ich denke, C ++ ist in erster Linie eine beschissene Sprache. Wenn Sie OOP verwenden möchten, schreiben Sie Java-Programme. C ++ tut nichts, um OOP-Paradigmen durchzusetzen, da Sie den direkten Speicherzugriff voll und ganz nutzen können.
Wenn Sie eine MCU haben, handelt es sich höchstwahrscheinlich um weniger als 100 KB Flash-Speicher. Sie möchten in einer Sprache programmieren, deren Speicherabstraktion folgendermaßen lautet: Wenn ich eine Variable oder ein Array deklariere, erhält sie Speicher, Punkt; malloc (alias "neues" Schlüsselwort in C ++) sollte mehr oder weniger für die Verwendung in eingebetteter Software gesperrt sein, außer vielleicht in seltenen Fällen, wenn ein Aufruf während des Programmstarts erfolgt.
Zum Teufel, es gibt (häufig) Zeiten in der eingebetteten Programmierung, in denen C nicht niedrig genug ist, und Sie müssen Dinge wie die Zuweisung von Variablen zu Registern und das Schreiben einer Inline-Assembly durchführen, um Ihre Interrupt-Service-Routinen (ISRs) zu straffen. Keywords wie "volatile" werden verdammt wichtig zu verstehen. Sie verbringen viel Zeit damit, den Speicher auf der Bit- Ebene zu manipulieren , nicht auf der Objektebene .
Warum sollten Sie sich vormachen, die Dinge seien einfacher als sie tatsächlich sind?
</ rant>
quelle