Gibt es einen Grund, C anstelle von C ++ für die eingebettete Entwicklung zu verwenden?


81

Frage

Ich habe zwei Compiler auf meiner Hardware C ++ und C89

Ich denke darüber nach, C ++ mit Klassen, aber ohne Polymorphismus zu verwenden (um vtables zu vermeiden). Die Hauptgründe, warum ich C ++ verwenden möchte, sind:

  • Ich bevorzuge die Verwendung von Inline-Funktionen anstelle von Makrodefinitionen.
  • Ich möchte Namespaces verwenden, da Präfixe den Code überladen.
  • Ich sehe C ++ ein bisschen sicherer, hauptsächlich wegen der Vorlagen und des ausführlichen Castings.
  • Ich mag überladene Funktionen und Konstruktoren (die für das automatische Casting verwendet werden) sehr.

Sehen Sie einen Grund, bei der Entwicklung für sehr begrenzte Hardware (4 KB RAM) bei C89 zu bleiben?

Fazit

Vielen Dank für Ihre Antworten, sie waren wirklich hilfreich!

Ich habe das Thema durchdacht und werde mich hauptsächlich an C halten, weil:

  1. Es ist einfacher, den tatsächlichen Code in C vorherzusagen, und dies ist sehr wichtig, wenn Sie nur 4 KB RAM haben.
  2. Mein Team besteht hauptsächlich aus C-Entwicklern, daher werden erweiterte C ++ - Funktionen nicht häufig verwendet.
  3. Ich habe einen Weg gefunden, Funktionen in meinem C-Compiler (C89) zu integrieren.

Es ist schwer, eine Antwort zu akzeptieren, da Sie so viele gute Antworten gegeben haben. Leider kann ich kein Wiki erstellen und akzeptieren, daher werde ich eine Antwort auswählen, die mich am meisten zum Nachdenken gebracht hat.


11
Eines: Stellen Sie immer klar, in welcher Sprache Sie schreiben. Versuchen Sie nicht, ein Programm in "C / C ++" zu schreiben. Schreiben Sie in C oder in C ++ und wissen Sie, welche Sprachfunktionen Sie verwenden und welche nicht.
David Thornley


Definieren Sie "eingebettete Entwicklung"
Marco van de Voort

@DavidThornley, Sie haben vielleicht Recht mit eingebetteten Fällen, aber ich war sehr angenehm überrascht, wie gut gemischter C & C ++ - Code zusammenspielt, wenn ich branchenübliche Open-Source-Apps wie Kamailio mit der STL erweitern möchte. Ich unterstütze offiziell diese Verwendung des STL- und C-Codes, da er eine enorme Funktionalität und Wartungsfreundlichkeit bietet und gleichzeitig nahezu keine Probleme verursacht (das Fehlen eingebetteter Strukturen in C ++ ist ein schreckliches Verbrechen gegen C ++ und sollte so schnell wie möglich behoben werden ).
user2548100

Denkanstöße, hier ist ein großartiger Artikel, in dem der Designer und Autor von ZeroMQ erläutert, warum er es bedauert, die Codebasis in C ++ anstelle von C geschrieben zu haben. Nicht das, was ich erwartet hatte, und aus Gründen, die an keiner anderen Stelle auf dieser Seite zu finden sind. 250bpm.com/blog:4
user2548100

Antworten:


46

Zwei Gründe für die Verwendung von C über C ++:

  1. Für viele eingebettete Prozessoren gibt es entweder keinen C ++ - Compiler oder Sie müssen dafür extra bezahlen.
  2. Ich habe die Erfahrung gemacht, dass ein erheblicher Teil der Ingenieure für eingebettete Software wenig oder gar keine Erfahrung mit C ++ hat - entweder aufgrund von (1) oder weil es in der Regel nicht in elektronischen Ingenieurabschlüssen unterrichtet wird - und es daher besser ist, sich daran zu halten was sie wissen.

In der ursprünglichen Frage und in einer Reihe von Kommentaren werden auch die 4 KB RAM erwähnt . Bei einem typischen eingebetteten Prozessor hängt die RAM-Größe (meistens) nicht von der Codegröße ab, da der Code gespeichert wird und von Flash ausgeführt wird.

Sicherlich ist die Menge an Code-Speicherplatz zu berücksichtigen, aber da neue, leistungsfähigere Prozessoren auf dem Markt erscheinen, ist dies weniger ein Problem als früher für alle außer den kostensensitivsten Projekten.

Zur Verwendung einer Teilmenge von C ++ zur Verwendung mit eingebetteten Systemen: Es gibt jetzt einen MISRA C ++ - Standard, der einen Blick wert sein kann.

EDIT: Siehe auch diese Frage , die zu einer Debatte über C vs C ++ für eingebettete Systeme führte.


2
Siehe meine längere Antwort unten: C ++ macht es sehr schwierig, konstante Daten in FLASH zu speichern.
Jakobengblom2

3
Ein potenziell guter Grund, C anstelle von C ++ zu verwenden, ist Cs Standard-ABI. Nur der Vollständigkeit halber.
Chris Lutz

66

Für ein sehr ressourcenbeschränktes Ziel wie 4 KB RAM würde ich das Wasser mit einigen Beispielen testen, bevor ich viel Aufwand unternehme, der nicht einfach in eine reine ANSI C-Implementierung zurückportiert werden kann.

Die Arbeitsgruppe Embedded C ++ schlug eine Standarduntermenge der Sprache und eine dazugehörige Standarduntermenge der Standardbibliothek vor. Ich habe diese Bemühungen leider aus den Augen verloren, als das C User's Journal starb. Es sieht so aus, als gäbe es einen Artikel bei Wikipedia und das Komitee existiert noch.

In einer eingebetteten Umgebung müssen Sie bei der Speicherzuweisung wirklich vorsichtig sein. Um diese Sorgfalt durchzusetzen, müssen Sie möglicherweise das Globale operator new()und seine Freunde für etwas definieren, das nicht einmal verknüpft werden kann, damit Sie wissen, dass es nicht verwendet wird. Die Platzierung newhingegen ist wahrscheinlich Ihr Freund, wenn sie mit Bedacht zusammen mit einem stabilen, threadsicheren und latenzgarantierten Zuweisungsschema verwendet wird.

Inline-Funktionen verursachen keine großen Probleme, es sei denn, sie sind groß genug, um eigentlich echte Funktionen zu sein. Natürlich hatten die Makros, die sie ersetzten, das gleiche Problem.

Auch Vorlagen verursachen möglicherweise kein Problem, es sei denn, ihre Instanziierung wird amok ausgeführt. Überprüfen Sie für jede Vorlage, die Sie verwenden, Ihren generierten Code (die Link-Map enthält möglicherweise genügend Hinweise), um sicherzustellen, dass nur die von Ihnen beabsichtigten Instanziierungen ausgeführt wurden.

Ein weiteres Problem, das auftreten kann, ist die Kompatibilität mit Ihrem Debugger. Es ist nicht ungewöhnlich, dass ein ansonsten verwendbarer Hardware-Debugger die Interaktion mit dem ursprünglichen Quellcode nur sehr eingeschränkt unterstützt. Wenn Sie in Assembly effektiv debuggen müssen, kann die interessante Namensverknüpfung von C ++ die Aufgabe zusätzlich verwirren.

RTTI, dynamische Casts, Mehrfachvererbung, starker Polymorphismus und Ausnahmen verursachen für ihre Verwendung einige Laufzeitkosten. Einige dieser Funktionen kosten das gesamte Programm, wenn sie verwendet werden, andere erhöhen lediglich das Gewicht der Klassen, die sie benötigen. Kennen Sie den Unterschied und wählen Sie erweiterte Funktionen mit Bedacht aus, wobei Sie mindestens eine flüchtige Kosten-Nutzen-Analyse kennen.

In einer kleinen eingebetteten Umgebung stellen Sie entweder eine direkte Verbindung zu einem Echtzeitkern her oder laufen direkt auf der Hardware. In beiden Fällen müssen Sie sicherstellen, dass Ihr Laufzeit-Startcode die C ++ - spezifischen Startaufgaben korrekt behandelt. Dies ist möglicherweise so einfach wie die Verwendung der richtigen Linker-Optionen. Da es jedoch üblich ist, die direkte Kontrolle über die Quelle zum Einschalt-Reset-Einstiegspunkt zu haben, müssen Sie dies möglicherweise überprüfen, um sicherzustellen, dass alles funktioniert. Auf einer ColdFire-Plattform, an der ich gearbeitet habe, wurden die Entwicklertools beispielsweise mit einem CRT0.S-Modul geliefert, in dem die C ++ - Initialisierer vorhanden waren, das jedoch auskommentiert wurde. Wenn ich es direkt aus der Box verwendet hätte, wäre ich von globalen Objekten verwirrt worden, deren Konstruktoren überhaupt nicht ausgeführt worden waren.

In einer eingebetteten Umgebung ist es häufig erforderlich, Hardwaregeräte zu initialisieren, bevor sie verwendet werden können. Wenn es kein Betriebssystem und keinen Bootloader gibt, ist dies Ihr Code, der dies tut. Sie müssen sich daran erinnern, dass Konstruktoren für globale Objekte ausgeführt werden, bevor sie main() aufgerufen werden. Daher müssen Sie Ihre lokale CRT0.S (oder eine entsprechende Entsprechung) ändern, um die Hardware-Initialisierung durchzuführen, bevor die globalen Konstruktoren selbst aufgerufen werden. Offensichtlich ist die Spitze main()viel zu spät.


1
Dieser braucht mehr Upvotes als ich geben kann! Gute Antwort.
Harper Shelby

+1, tolle Antwort. Ich denke jedoch, dass die einzige Vorlageninstanziierung, über die Sie sich wirklich Sorgen machen müssen, die (relativ seltene) rekursive Art ist - für die "normale" nicht rekursive Art entspricht die Instanziierung dem Code, den Sie ohnehin manuell eingegeben hätten.
j_random_hacker

2
@j_random_hacker, wahr. Die Gewohnheit von Vorlagen kann jedoch zu gelegentlichen Überraschungen führen, wenn eine zweite (oder dritte) Instanziierung auftritt, bei der der richtige Typenzwang am Verwendungsort dies möglicherweise verhindert hat. Es ist nur etwas, worauf man achten muss.
RBerteig

@RBerteig: Guter Punkt, Vorlagen erlauben weniger Möglichkeiten des Typzwangs => Möglicherweise werden deutlichere Instanziierungen erzeugt als mit Nicht-Vorlagencode.
j_random_hacker

26

Nein. Alle C ++ - Sprachfunktionen, die Probleme verursachen können (Laufzeitpolymorphismus, RTTI usw.), können während der eingebetteten Entwicklung vermieden werden. Es gibt eine Community von eingebetteten C ++ - Entwicklern (ich erinnere mich, dass ich Spalten von eingebetteten Entwicklern gelesen habe, die C ++ im alten C / C ++ - Benutzerjournal verwendet haben), und ich kann mir nicht vorstellen, dass sie sehr lautstark wären, wenn die Wahl so schlecht wäre.


20

Der technische Bericht zur C ++ - Leistung ist ein guter Leitfaden für diese Art von Dingen. Beachten Sie, dass es einen Abschnitt zu Problemen mit der eingebetteten Programmierung gibt!

Auch ++ zur Erwähnung von Embedded C ++ in den Antworten. Der Standard entspricht nicht zu 100% meinem Geschmack, ist jedoch eine gute Referenz, wenn Sie entscheiden, welche Teile von C ++ Sie löschen möchten.

Während der Programmierung für kleine Plattformen deaktivieren wir Ausnahmen und RTTI, vermeiden virtuelle Vererbung und achten genau auf die Anzahl der virtuellen Funktionen, die wir herumliegen.

Ihr Freund ist jedoch die Linker-Map: Überprüfen Sie sie regelmäßig, und Sie werden feststellen, dass Codequellen und statischer Speicher schnell aufblähen.

Danach gelten die Standardüberlegungen zur dynamischen Speichernutzung: In einer Umgebung, die so eingeschränkt ist wie die von Ihnen erwähnte, möchten Sie möglicherweise überhaupt keine dynamischen Zuordnungen verwenden. Manchmal können Sie mit Speicherpools für kleine dynamische Zuordnungen oder einer "rahmenbasierten" Zuweisung davonkommen, bei der Sie einen Block vorab zuweisen und das Ganze später wegwerfen.


17

Ich empfehle die Verwendung des C ++ - Compilers, schränke jedoch die Verwendung von C ++ - spezifischen Funktionen ein. Sie können wie C in C ++ programmieren (die C-Laufzeit ist in C ++ enthalten, obwohl Sie in den meisten eingebetteten Anwendungen die Standardbibliothek sowieso nicht verwenden).

Sie können einfach C ++ - Klassen usw. verwenden

  • Beschränken Sie die Verwendung virtueller Funktionen (wie Sie gesagt haben)
  • Beschränken Sie die Verwendung von Vorlagen
  • Bei einer eingebetteten Plattform sollten Sie den Operator new überschreiben und / oder die Platzierung new für die Speicherzuweisung verwenden.

7
Wenn Sie bereits C schreiben, können Sie es natürlich auch offiziell machen.
Chuck

5
Warum beschränken Sie die Verwendung von Vorlagen? Ich habe gedacht, dass Vorlagenfunktionen in eingebetteten Systemen sehr hilfreich sein können, um beispielsweise Schleifen abzuwickeln.
Piotr Czapla

1
Sie können weiterhin Vorlagen verwenden, aber ich würde sehr vorsichtig mit ihnen sein, da sie die Größe der Ausgabe-Binärdatei schnell erhöhen können. Wenn Ihr Code direkt aus dem ROM oder ähnlichem ausgeführt wird und Sie über ausreichend Speicherplatz im ROM verfügen, müssen Sie natürlich vorsichtig sein, was Sie mit Vorlagen tun (bei jeder Vorlageninstanz wird im Grunde der gesamte Vorlagencode erneut dupliziert in der endgültigen ausführbaren Datei im schlimmsten Fall).
Arke

15

Als Firmware- / Embedded-System-Ingenieur kann ich Ihnen einige Gründe nennen, warum C immer noch die erste Wahl gegenüber C ++ ist, und ja, ich spreche beide fließend.

1) Einige Ziele, auf denen wir entwickeln, verfügen über 64 KB RAM für Code und Daten. Sie müssen also sicherstellen, dass jede Byte zählt. Ja, ich habe mich mit der Codeoptimierung befasst, um 4 Bytes zu sparen, die mich 2 Stunden gekostet haben 2008.

2) Jede C-Bibliotheksfunktion wird aufgrund der Größenbeschränkung überprüft, bevor wir sie in den endgültigen Code aufnehmen. Daher bevorzugen wir, dass Benutzer nicht dividieren (kein Hardware-Teiler, daher wird eine große Bibliothek benötigt), malloc (weil wir keinen Heap haben) verwenden Der gesamte Speicher wird aus dem Datenpuffer in einem 512-Byte-Block zugewiesen und muss auf Code überprüft werden. Denken Sie daran, dass jede Bibliotheksfunktion, die Sie verwenden, zählt.

3) Schon mal was von dem Begriff Overlay gehört? Sie haben so wenig Code-Speicherplatz, dass Sie manchmal Dinge mit einem anderen Code-Satz austauschen müssen. Wenn Sie eine Bibliotheksfunktion aufrufen, muss die Bibliotheksfunktion resident sein. Wenn Sie es nur in einer Überlagerungsfunktion verwenden, verschwenden Sie viel Platz, wenn Sie zu viele objektorientierte Methoden verwenden. Nehmen Sie also keine C-Bibliotheksfunktion an, geschweige denn, dass C ++ akzeptiert wird.

4) Casting und sogar Packen (wenn die nicht ausgerichtete Datenstruktur die Wortgrenze überschreitet) sind aufgrund des eingeschränkten Hardware-Designs (dh einer ECC-Engine, die auf eine bestimmte Weise verkabelt ist) oder zur Bewältigung eines Hardware-Fehlers erforderlich. Sie können nicht zu viel implizit annehmen. Warum sollten Sie es also zu sehr objektorientieren?

5) Worst-Case-Szenario: Wenn Sie einige der objektorientierten Methoden eliminieren, müssen Sie überlegen, bevor Sie Ressourcen verwenden, die explodieren können (dh 512 Bytes auf einem Stapel anstatt aus einem Datenpuffer zuweisen), und einige der potenziellen Worst-Case-Szenarien verhindern werden nicht auf den gesamten Codepfad getestet oder eliminiert.

6) Wir verwenden viel Abstraktion, um Hardware von Software fernzuhalten und Code so portabel wie möglich und simulationsfreundlich zu machen. Der Hardwarezugriff muss in eine Makro- oder Inline-Funktion eingebunden sein, die bedingt zwischen verschiedenen Plattformen kompiliert wird. Der Datentyp muss als Bytegröße und nicht als zielspezifische Umwandlung umgewandelt werden. Eine direkte Zeigerverwendung ist nicht zulässig (da einige Plattformen davon ausgehen, dass die zugeordnete Speicher-E / A die ist wie Datenspeicher) usw.

Ich kann mir mehr vorstellen, aber Sie haben die Idee. Wir Firmware-Leute haben zwar objektorientiertes Training, aber die Aufgabe des eingebetteten Systems kann so hardwareorientiert und niedrig sein, dass es von Natur aus nicht hoch oder abstrakt ist.

Übrigens, jeder Firmware-Job, bei dem ich gearbeitet habe, verwendet die Quellcodeverwaltung. Ich weiß nicht, woher Sie diese Idee haben.

-Einiger Firmware-Typ von SanDisk.


Anfang der 90er Jahre war Overlay eine sehr beliebte Technik (zumindest in der DOS-Welt)
Psihodelia

Gute Punkte Shing. C ++ fühlt sich wie ein Sumo-Wrestler in einer Telefonzelle bei Projekten an, bei denen die Funktionalität und die Ressourcen noch eingeschränkter sind.

3
Ich glaube, diese Antwort ist sehr subjektiv und liefert keine konkreten Gründe.
Venemo

1
C ++ bedeutet nicht unbedingt "objektorientiert".
Martin Bonner unterstützt Monica

1
Es ist einfach nicht wahr, dass die Aufgabe des eingebetteten Systems von Natur aus nicht abstrahierbar ist. Sie haben es selbst in Punkt 6) gesagt: "Wir verwenden viel Abstraktion, um hw von sw abzuhalten und Code so portabel wie möglich zu machen" :-) Übrigens: "Abstraktion" bedeutet nicht unbedingt "Polymorphismus".
Daniele Pallastrelli

9

Meine persönliche Präferenz ist C, weil:

  • Ich weiß, was jede Codezeile tut (und was kostet)
  • Ich kenne C ++ nicht gut genug, um zu wissen, was jede Codezeile tut (und was sie kostet).

Warum sagen die Leute das? Sie wissen nicht , was jede Zeile von C tut, es sei denn, Sie überprüfen die ASM-Ausgabe. Gleiches gilt für C ++.

Was bringt diese unschuldige Aussage zum Beispiel hervor:

a[i] = b[j] * c[k];

Es sieht ziemlich unschuldig aus, aber ein gcc-basierter Compiler erzeugt diesen Asm für ein 8-Bit-Mikro

CLRF 0x1f, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1f, F, ACCESS
MOVWF 0x1e, ACCESS
MOVLW 0xf9
MOVF 0xfdb, W, ACCESS
ADDWF 0x1e, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfa
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1f, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x1c
NOP
MOVFF 0xfef, 0x1d
NOP
MOVLW 0x1
CLRF 0x1b, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1b, F, ACCESS
MOVWF 0x1a, ACCESS
MOVLW 0xfb
MOVF 0xfdb, W, ACCESS
ADDWF 0x1a, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfc
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1b, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x18
NOP
MOVFF 0xfef, 0x19
NOP
MOVFF 0x18, 0x8
NOP
MOVFF 0x19, 0x9
NOP
MOVFF 0x1c, 0xd
NOP
MOVFF 0x1d, 0xe
NOP
CALL 0x2142, 0
NOP
MOVFF 0x6, 0x16
NOP
MOVFF 0x7, 0x17
NOP
CLRF 0x15, ACCESS
RLCF 0xfdf, W, ACCESS
ANDLW 0xfe
RLCF 0x15, F, ACCESS
MOVWF 0x14, ACCESS
MOVLW 0xfd
MOVF 0xfdb, W, ACCESS
ADDWF 0x14, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfe
MOVF 0xfdb, W, ACCESS
ADDWFC 0x15, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0x16, 0xfee
NOP
MOVFF 0x17, 0xfed
NOP

Die Anzahl der erstellten Anweisungen hängt massiv ab von:

  • Die Größen von a, b und c.
  • ob diese Zeiger auf dem Stapel gespeichert sind oder global sind
  • ob i, j und k auf dem Stapel sind oder global sind

Dies gilt insbesondere in der winzigen eingebetteten Welt, in der Prozessoren einfach nicht für C eingerichtet sind. Meine Antwort wäre also, dass C und C ++ genauso schlecht sind wie die anderen, es sei denn, Sie untersuchen immer die asm-Ausgabe, in diesem Fall sind genauso gut wie die anderen.

Hugo


2
Beachten Sie auch, dass sich in der Mitte all dessen, was die Multiplikationsfunktion tatsächlich aufruft, eine Aufrufanweisung befindet. Der ganze Code ist nicht einmal eine Multiplikationsanweisung!
Raketenmagnet

Jemand, der mit einem Mikro vertraut ist, kennt normalerweise eine einfache Möglichkeit, jeden Teil des C-Codes isoliert zu verarbeiten, und ein anständiger Compiler sollte keinen schlechteren Code produzieren. Der obige Ausdruck könnte nur dann effizient verarbeitet werden, wenn Annahmen getroffen werden, die für einen C-Compiler möglicherweise nicht geeignet sind.
Supercat

8

Ich habe gehört, dass einige Leute C für eingebettete Arbeit bevorzugen, weil es einfacher ist und daher einfacher ist, den tatsächlich generierten Code vorherzusagen.

Ich persönlich würde denken, dass das Schreiben von C ++ im C-Stil (Verwendung von Vorlagen für die Typensicherheit) Ihnen viele Vorteile bringen würde, und ich sehe keinen wirklichen Grund, dies nicht zu tun.


+1, Transparenz ist immer wichtig und wahrscheinlich auch für eine eingeschränkte Umgebung mit (vermutlich) eingeschränkten Debugging-Tools.
j_random_hacker

7

Ich sehe keinen Grund, C anstelle von C ++ zu verwenden. Was auch immer Sie in C tun können, Sie können es auch in C ++ tun. Wenn Sie den Aufwand für VMT vermeiden möchten, verwenden Sie keine virtuellen Methoden und keinen Polymorphismus.

C ++ kann jedoch einige sehr nützliche Redewendungen ohne Overhead bereitstellen. Einer meiner Favoriten ist RAII. Klassen sind nicht unbedingt teuer in Bezug auf Speicher oder Leistung ...


6

Ich habe Code für ARM7 Embedded Paltform auf IAR Workbench geschrieben. Ich empfehle dringend, sich auf Vorlagen zu verlassen, um die Optimierung der Kompilierungszeit und die Pfadvorhersage durchzuführen. Vermeiden Sie dynamisches Casting wie Pest. Nutzen Sie Merkmale / Richtlinien zu Ihrem Vorteil, wie in Andrei Alexandrescus Buch Modern C ++ Design beschrieben .

Ich weiß, es kann schwer zu lernen sein, aber ich bin auch sicher, dass Ihr Produkt von diesem Ansatz profitieren wird.


5

Ein guter Grund und manchmal der einzige Grund ist, dass es noch keinen C ++ - Compiler für das spezifische eingebettete System gibt. Dies ist beispielsweise bei Microchip PIC- Mikrocontrollern der Fall . Sie sind sehr einfach zu schreiben und haben einen kostenlosen C-Compiler (eigentlich eine leichte Variante von C), aber es ist kein C ++ - Compiler in Sicht.


1
Comeau Computing ( comeaucomputing.com ) verkauft einen C ++ - Compiler, der an C. kompiliert wird
Thomas L Holaday

3
Eww. Diese Seite wollte kotzen.
Shoosh

@shoosh: Ja, das Site-Design ist schrecklich. Der Compiler selbst gilt jedoch als führend auf diesem Gebiet, zumindest in Bezug auf die Standardkonformität (ich habe keine Informationen über die Leistung).
j_random_hacker

Diese Website gibt mir das Gefühl, in einem lebenden, atmenden und SEHR wütenden Obstsalat gefangen zu sein.
Tim Post

5

Für ein System, das auf 4 KB RAM beschränkt ist, würde ich C verwenden, nicht C ++, nur damit Sie sicher sein können, alles zu sehen, was vor sich geht. Die Sache mit C ++ ist, dass es sehr einfach ist, weit mehr Ressourcen (sowohl CPU als auch Speicher) zu verwenden, als es aussieht, als würde man einen Blick auf den Code werfen. (Oh, ich werde einfach ein anderes BlerfObject erstellen, um das zu tun ... whoops! Aus dem Gedächtnis!)

Sie können dies in C ++ tun, wie bereits erwähnt (keine RTTI, keine vtables usw. usw.), aber Sie werden genauso viel Zeit damit verbringen, sicherzustellen, dass Ihre C ++ - Nutzung nicht von Ihnen abweicht, wie Sie es in C tun würden .


2
Ihr letzter Satz ist richtig, aber irrelevant, da C ++ gegenüber C andere Vorteile bietet, die das Gleichgewicht (möglicherweise) beeinflussen. Piotr hat bereits einige dieser (kostengünstigen) Vorteile erwähnt.
Konrad Rudolph

5

Der menschliche Geist befasst sich mit Komplexität, indem er so viel wie möglich bewertet und dann entscheidet, worauf es ankommt, und den Rest verwirft oder abwertet. Dies ist die gesamte Grundlage für das Branding im Marketing und vor allem für Ikonen.

Um dieser Tendenz entgegenzuwirken, ziehe ich C C ++ vor, weil es Sie dazu zwingt, über Ihren Code nachzudenken und wie er enger mit der Hardware interagiert - unerbittlich nahe.

Aus langjähriger Erfahrung glaube ich, dass C Sie dazu zwingt, bessere Lösungen für Probleme zu finden, teilweise indem Sie aus dem Weg gehen und Sie nicht dazu zwingen, viel Zeit damit zu verschwenden, eine Einschränkung zu erfüllen, die einige Compiler-Writer für eine gute Idee hielten oder herauszufinden, was "unter der Decke" los ist.

In diesem Sinne verbringen Sie bei Low-Level-Sprachen wie C viel Zeit damit, sich auf die Hardware zu konzentrieren und gute Datenstruktur- / Algorithmus-Bundles zu erstellen, während Sie bei High-Level-Sprachen viel Zeit damit verbringen, sich am Kopf zu kratzen und sich zu fragen, was dort vor sich geht und warum Sie in Ihrem spezifischen Kontext und Ihrer Umgebung nichts völlig Vernünftiges tun können. Es ist KEIN produktiver Zeitaufwand, Ihren Compiler zur Übermittlung zu zwingen (starkes Tippen ist der schlimmste Übeltäter).

Ich passe wahrscheinlich gut in die Programmierform - ich mag Kontrolle. Meiner Meinung nach ist das kein Persönlichkeitsfehler für einen Programmierer. Kontrolle ist das, wofür wir bezahlt werden. Genauer gesagt, FLAWLESSLY Kontrolle. C gibt Ihnen viel mehr Kontrolle als C ++.


Martin Sistrik, der Autor von ZeroMQ, machte fast den gleichen Punkt in seiner Diskussion darüber, warum er wünscht, er hätte ZeroMQ jetzt in C anstelle von C ++ geschrieben. Überprüfen Sie es heraus 250bpm.com/blog:8
user2548100

3

Persönlich mit 4 KB Arbeitsspeicher würde ich sagen, dass Sie mit C ++ nicht viel mehr Kilometer herausholen. Wählen Sie also einfach diejenige aus, die als beste Compiler- / Laufzeitkombination für den Job erscheint, da die Sprache wahrscheinlich nicht viel ausmacht.

Beachten Sie, dass es sowieso auch nicht nur um Sprache geht, da auch die Bibliothek wichtig ist. Oft haben C-Bibliotheken eine etwas kleinere Mindestgröße, aber ich könnte mir vorstellen, dass eine C ++ - Bibliothek, die auf die eingebettete Entwicklung abzielt, reduziert wird. Testen Sie sie also unbedingt.


2

C gewinnt bei der Portabilität - weil es in der Sprachspezifikation weniger mehrdeutig ist; Dies bietet eine viel bessere Portabilität und Flexibilität für verschiedene Compiler usw. (weniger Kopfschmerzen).

Wenn Sie die C ++ - Funktionen nicht nutzen möchten, um einen Bedarf zu decken, wählen Sie C.


Ob die Sprache eindeutig ist , hängt davon ab, ob man hält es wie die Dinge anzugeben , die die gesunden Menschenverstand betrachtet werden verwendet, aber heutzutage ist nicht [zB , dass ein Compiler für 32-Bit - silent-Rundum - Zweierkomplement-Hardware sollte so etwas wie verarbeiten unsigned mul(unsigned short x, unsigned short y) { return x*y;}hat keine Nebenwirkungen, selbst wenn das Produkt 2147483647 überschreitet oder wenn es void get_float_bits(float *fp, uint32_t n) { *(uint32_t)fp = n; }als mögliche Änderung des Wertes von a float] angesehen werden sollte.
Supercat

2

Sehen Sie einen Grund, bei der Entwicklung für sehr begrenzte Hardware (4 KB RAM) bei C89 zu bleiben?

Persönlich, wenn es um eingebettete Anwendungen geht (Wenn ich Embedded sage, meine ich heute nicht winCE, iPhone usw. aufgeblähte eingebettete Geräte). Ich meine ressourcenbeschränkte Geräte. Ich bevorzuge C, obwohl ich auch ziemlich viel mit C ++ gearbeitet habe.

Das Gerät, über das Sie sprechen, verfügt beispielsweise über 4 KB RAM. Aus diesem Grund würde ich C ++ nicht in Betracht ziehen. Sicher, Sie sind möglicherweise in der Lage, mit C ++ etwas Kleines zu entwerfen und die Verwendung in Ihrer Anwendung einzuschränken, wie andere Beiträge vorgeschlagen haben, aber C ++ "könnte" möglicherweise dazu führen, dass Ihre Anwendung unter dem Deckmantel kompliziert / aufgebläht wird.

Wirst du statisch verlinken? Möglicherweise möchten Sie eine statische Dummy-Anwendung mit c ++ mit c vergleichen. Das kann dazu führen, dass Sie stattdessen C in Betracht ziehen. Wenn Sie jedoch in der Lage sind, eine C ++ - Anwendung innerhalb Ihrer Speicheranforderungen zu erstellen, entscheiden Sie sich dafür.

IMHO, Im Allgemeinen möchte ich in eingebetteten Anwendungen alles wissen, was vor sich geht. Wer verwendet Speicher- / Systemressourcen, wie viel und warum? Wann befreien sie sie?

Bei der Entwicklung für ein Ziel mit einer X-Menge an Ressourcen, CPU, Speicher usw. versuche ich, bei der Verwendung dieser Ressourcen auf der unteren Seite zu bleiben, da Sie nie wissen, welche zukünftigen Anforderungen sich ergeben werden, sodass Sie dem Projekt mehr Code hinzufügen müssen sollte eine einfache kleine Anwendung sein, wird aber viel größer.


1
Ich werde auf jeden Fall die beiden Compiler vergleichen. (Übrigens kann ich nicht dynamisch verknüpfen, da es kein Betriebssystem gibt)
Piotr Czapla

2

Meine Wahl wird normalerweise von der C-Bibliothek bestimmt, die wir verwenden möchten. Diese wird basierend auf den Anforderungen des Geräts ausgewählt. Also, 9/10 mal ... es endet mit uclibc oder newlib und C. Der Kernel, den wir verwenden, hat auch einen großen Einfluss darauf, oder wenn wir unseren eigenen Kernel schreiben.

Es ist auch eine Wahl der Gemeinsamkeiten. Die meisten guten C-Programmierer haben kein Problem mit C ++ (obwohl sich viele die ganze Zeit über beschweren, dass sie es verwenden). Aber ich habe nicht festgestellt, dass das Gegenteil der Fall ist (meiner Erfahrung nach).

In einem Projekt, an dem wir arbeiten (das einen Grundkern beinhaltet), werden die meisten Dinge in C erledigt, jedoch wurde ein kleiner Netzwerkstapel in C ++ implementiert, da es einfach und weniger problematisch war, Netzwerke mit C ++ zu implementieren.

Das Endergebnis ist, dass das Gerät entweder funktioniert und Abnahmetests besteht oder nicht. Wenn Sie foo in xx-Stapel- und yy-Heap-Einschränkungen mit der Sprache z implementieren können, wählen Sie alles, was Sie produktiver macht.

Meine persönliche Präferenz ist C, weil:

  • Ich weiß, was jede Codezeile tut (und was kostet)
  • Ich kenne C ++ nicht gut genug, um zu wissen, was jede Codezeile tut (und was sie kostet).

Ja, ich bin mit C ++ vertraut, aber ich weiß es nicht so gut wie Standard C.

Wenn Sie das Gegenteil sagen können, verwenden Sie das, was Sie wissen :) Wenn es funktioniert, Tests besteht usw. Was ist das Problem?


2
> # Ich weiß, was jede Codezeile tut (und was sie kostet). Nachdem ich Compiler geschrieben habe, wäre ich mir dessen nicht so sicher ... Ein guter C-Compiler kann Ihrem Code ziemlich überraschende Dinge antun, da er einen schönen globalen Überblick über hat Dinge. Es wird nicht zeilenweise kompiliert.
Jakobengblom2

@ jakobengblom2: Für die Embedded-Entwicklung ist eine konsistente Leistung oft wichtiger als eine maximale Leistung. Wenn versucht wird, festzustellen, ob ein Code die Timing-Anforderungen erfüllt, ist es weniger hilfreich, wenn ein Compiler Optimierungen verwendet, die in "Test" -Firmware verwendet werden können, die in echter Firmware nicht funktioniert.
Supercat

2

Wie viel ROM / FLASH hast du?

4 KB RAM können immer noch bedeuten, dass Hunderte von Kilobyte FLASH zum Speichern des tatsächlichen Codes und der statischen Daten vorhanden sind. RAM in dieser Größe ist in der Regel nur für Variablen gedacht, und wenn Sie mit diesen vorsichtig sind, können Sie ein ziemlich großes Programm in Bezug auf Codezeilen in den Speicher einfügen.

C ++ erschwert jedoch das Einfügen von Code und Daten in FLASH aufgrund der Laufzeitkonstruktionsregeln für Objekte. In C kann eine konstante Struktur leicht in den FLASH-Speicher gestellt und als hardwarekonstantes Objekt aufgerufen werden. In C ++ würde ein konstantes Objekt erfordern, dass der Compiler den Konstruktor zur Kompilierungszeit auswertet, was meiner Meinung nach immer noch über das hinausgeht, was ein C ++ - Compiler kann (theoretisch könnte man es tun, aber in der Praxis ist es sehr, sehr schwierig). .

In einer Umgebung mit "kleinem RAM" und "großem FLASH" würde ich jeden Tag mit C arbeiten. Beachten Sie, dass i C99 eine gute Zwischenauswahl ist, die die meisten netten C ++ - Funktionen für nicht klassenbasierten Code bietet.


3
Gibt es einen Grund, warum dieselbe Struktur, die in C in den Flash-Speicher gestellt wird, nicht auch in C ++ in Flash landet? Sie müssen nicht haben einen Konstruktor Ihre Struktur in C ++ in den.
Jalf

1

Im Allgemeinen nein. C ++ ist eine super Menge von C. Dies gilt insbesondere für neue Projekte.

Sie sind auf dem richtigen Weg, um C ++ - Konstrukte zu vermeiden, die in Bezug auf CPU-Zeit und Speicherbedarf teuer sein können.

Beachten Sie, dass einige Dinge wie Polymorphismus sehr wertvoll sein können - das sind im Wesentlichen Funktionszeiger. Wenn Sie feststellen, dass Sie sie brauchen, setzen Sie sie mit Bedacht ein.

Eine gute (gut gestaltete) Ausnahmebehandlung kann Ihre eingebettete App zuverlässiger machen als eine App, die Dinge mit herkömmlichen Fehlercodes behandelt.


2
C ++ ist streng genommen keine strikte Obermenge von C, aber dieses spezielle Detail ist in diesem Zusammenhang nicht besonders wichtig.
Arafangion

1

Bei Problemen mit der Speicherzuweisung kann ich die Verwendung der Quantum Platform und ihres Zustandsmaschinenansatzes empfehlen, da sie alles zuweist, was Sie zum Zeitpunkt der Initialisierung benötigen. Es hilft auch, Konfliktprobleme zu lindern.

Dieses Produkt läuft sowohl unter C als auch unter C ++.


1

Einige sagen, dass C-Compiler viel effizienteren Code generieren können, da sie die erweiterten C ++ - Funktionen nicht unterstützen müssen und daher bei ihren Optimierungen aggressiver sein können.

In diesem Fall möchten Sie natürlich die beiden spezifischen Compiler testen.


1
Verwandte: Das Schlüsselwort "Einschränken" ist meines Wissens das einzige optimierungsbezogene C-Konstrukt, das in C ++ fehlt (auch in C ++ 11).
Johan Lundberg

1

Der einzige Grund, C IMHO zu bevorzugen, wäre, wenn der C ++ - Compiler für Ihre Plattform nicht in einem guten Zustand ist (fehlerhaft, schlechte Optimierung usw.).


Was ist mit der Speicher- / Ressourcennutzung?
Steve Lazaridis

Was ist damit? Es gibt keinen Grund für einen C ++ - Compiler, weniger effizienten Code als einen C-Compiler zu erzeugen, es sei denn, der Code verwendet RTTI, was auf eingebetteten Systemen niemand tut.
Nemanja Trifunovic


1

Sie haben Inline in C99. Vielleicht magst du ctors, aber das Geschäft, dtors richtig zu machen, kann chaotisch sein. Wenn der verbleibende einzige Grund, C nicht zu verwenden, Namespaces sind, würde ich mich wirklich an C89 halten. Dies liegt daran, dass Sie es möglicherweise auf eine etwas andere eingebettete Plattform portieren möchten. Sie können später in C ++ mit demselben Code schreiben. Beachten Sie jedoch Folgendes: C ++ ist KEINE Obermenge von C. Ich weiß, dass Sie gesagt haben, Sie haben einen C89-Compiler, führt diesen C ++ - Vergleich jedoch trotzdem mit C99 durch, da das erste Element beispielsweise für jedes C seit K & R gilt.

Größe von 'a' > 1 in C, nicht in C ++. In C haben Sie VLA-Arrays mit variabler Länge. Beispiel: func (int i) {int a [i] . In C haben Sie VAM-Variablenarray-Mitglieder. Beispiel: struct {int b; int m [];} .


1
Ich möchte erwähnen, dass Sie in C (sizeof 'a') == sizeof (int) haben. Während in C ++ Sie haben diese 1 == Größe von 'a'
hept

1
Ganz zu schweigen von "int * a; ...; a = (int *) malloc (size * sizeof (int));" ist die Methode zum Zuweisen von Speicher, der in C und C ++ funktioniert und in keinem von beiden verwendet werden sollte. Verwenden Sie entweder "a = malloc (size * sizeof (int));" oder "vector <int> a (size);" oder sogar "int * a = new int [size];" stattdessen.
David Thornley

1
Ich verstehe Ihren Standpunkt zu Dtors nicht. Der ganze Punkt über sie ist, dass sie den Rest Ihres Codes viel weniger chaotisch machen.
Jalf

1
+1, nicht sicher, warum dieser Beitrag so einen schlechten Ruf bekam. Aber ich stimme Jalf zu, Destruktoren vereinfachen den Code erheblich, wenn sie auf die richtige Weise (RAII) verwendet werden. (Man könnte sagen, dass sie "hinter den Kulissen arbeiten", aber sie machen nur Dinge, die der richtige Code sowieso manuell machen würde.)
j_random_hacker

1
Ich denke, die Dinge, auf die ich hinweise, sind für die Frage sehr relevant. Ich halte mich auch an meine Aussage, dass dtors schwierig sein können, und der Grund ist genau, dass es automatisch geschieht. Ich habe Minuspunkte - das ist wirklich harch. Ich denke, es liegt daran, dass ich nicht "JA, GO C ++ its GREAT" sage.
Hept

1

Das hängt vom Compiler ab.

Nicht alle eingebetteten Compiler implementieren C ++ vollständig, und selbst wenn dies der Fall ist, können sie möglicherweise das Aufblähen von Code nicht gut vermeiden (was bei Vorlagen immer ein Risiko darstellt). Testen Sie es mit einigen kleineren Programmen, um festzustellen, ob Probleme auftreten.

Aber angesichts eines guten Compilers gibt es keinen Grund, C ++ nicht zu verwenden.


1

Ich möchte nur sagen, dass es kein System mit "UNBEGRENZTEN" Ressourcen gibt. Alles auf dieser Welt ist begrenzt und JEDE Anwendung sollte die Ressourcennutzung berücksichtigen, unabhängig davon, ob es sich um ASM, C, JAVA oder JavaScript handelt. Die Dummies, die ein paar Mbs "nur um sicher zu gehen" zuweisen, machen iPhone 7, Pixel und andere Geräte extrem träge. Egal ob Sie 4kb oder 40 Gb haben.

Aber von einer anderen Seite, um sich der Verschwendung von Ressourcen zu widersetzen, ist eine Zeit erforderlich, um diese Ressourcen zu schonen. Wenn es 1 Woche länger dauert, eine einfache Sache in C zu schreiben, um ein paar Ticks und ein paar Bytes zu sparen, anstatt C ++ zu verwenden, das bereits implementiert, getestet und verteilt wurde. Warum die Mühe? Es ist wie der Kauf eines USB-Hubs. Ja, du kannst es selbst machen, aber wird es besser? zuverlässiger? billiger, wenn Sie Ihre Zeit zählen?

Nur ein Nebengedanke - selbst die Stromversorgung Ihrer Steckdose ist nicht unbegrenzt. Versuchen Sie herauszufinden, woher es kommt, und Sie werden hauptsächlich sehen, dass es etwas verbrennt. Das Gesetz von Energie und Material gilt weiterhin: Es erscheint oder verschwindet kein Material oder keine Energie, sondern wandelt sich um.


0

Ich habe gerade ein Beispiel für die Verwendung von ISO C ++ für die eingebettete Entwicklung gefunden, das für jemanden interessant sein könnte, der die Entscheidung trifft, wann immer er C ++ oder C verwendet.

Es wurde von Bjarne Stroustrup auf seiner Homepage zur Verfügung gestellt :

Einen Blick darauf, wie ISO C ++ für die ernsthafte Programmierung eingebetteter Systeme verwendet werden kann, finden Sie in den C ++ - Codierungsstandards für JSF-Luftfahrzeuge .


Nun, fliegende Dinge haben normalerweise PPC-Prozessoren mit Gigabyte RAM. Nicht Ihr durchschnittliches eingebettetes System mit eingeschränkten Ressourcen.
Jakobengblom2

0

Unterschiedlicher Antwortbeitrag zu einem anderen Aspekt der Frage:

"malloc"

Einige frühere Antworten sprechen ziemlich viel darüber. Warum glaubst du überhaupt, dass dieser Anruf existiert? Für eine wirklich kleine Plattform ist malloc in der Regel nicht verfügbar oder definitiv optional. Die Implementierung einer dynamischen Speicherzuweisung ist in der Regel sinnvoll, wenn Sie ein RTOS im unteren Bereich Ihres Systems haben - bis dahin ist dies jedoch rein gefährlich.

Ohne kann man sehr weit kommen. Denken Sie nur an all die alten FORTRAN-Programme, die nicht einmal einen richtigen Stapel für lokale Variablen hatten ...


0

Es gibt eine Reihe verschiedener Controller-Hersteller auf der ganzen Welt. Wenn Sie sich deren Design und die Befehlssätze ansehen, die für die Konfiguration verwendet werden müssen, kann dies zu vielen Problemen führen. Der Hauptnachteil der Assemblersprache ist, dass die Maschine / Architektur abhängig ist. Es ist wirklich eine große Herausforderung für einen Entwickler, alle dort aufgeführten Anweisungen auswendig zu lernen, um die Codierung für verschiedene Controller durchzuführen. Aus diesem Grund wurde C in der Embedded-Entwicklung immer beliebter, da C hoch genug ist, um die Algorithmen und Datenstrukturen von hardwareabhängigen Details zu abstrahieren, wodurch der Quellcode auf eine Vielzahl von Zielhardware, architekturunabhängiger Sprache und sehr einfach zu portieren ist Konvertieren und pflegen Sie den Code. Wir sehen jedoch einige (objektorientierte) Hochsprachen wie C, C ++, Python, Java usw.


0

Ich empfehle C ++ mit Einschränkungen und Hinweisen.

  1. Time-to-Market und Wartbarkeit. Die C ++ - Entwicklung ist einfacher und schneller. Wenn Sie sich also in der Entwurfsphase befinden, wählen Sie einen Controller, der groß genug ist, um C ++ zu verwenden. (Beachten Sie, dass ein Markt mit hohem Volumen so niedrige Kosten wie möglich erfordert, wenn Sie diese Wahl nicht treffen können.)

  2. Geschwindigkeit. C kann schneller als C ++ sein, aber stellen Sie sicher, dass der Geschwindigkeitsgewinn nicht groß ist. Sie können also mit C ++ gehen. Entwickeln Sie Ihre Algorithmen, testen Sie sie und beschleunigen Sie sie nur bei Bedarf (!). Verwenden Sie Profiler, um die Engpässe zu erkennen und sie extern "C" umzuschreiben , um die C-Geschwindigkeit zu erreichen. (Wenn es diesen Teil immer noch langsam implementiert, implementieren Sie ihn in ASM.)

  3. Binärgröße. Die C ++ - Codes sind größer, aber hier ist eine großartige Antwort , die die Details verrät. Die Größe der kompilierten Binärdatei eines bestimmten C-Codes ist gleich, unabhängig davon, ob sie mit dem C- oder dem C ++ - Compiler kompiliert wurde. "Die Größe der ausführbaren Datei hängt kaum von der Sprache ab, sondern von den Bibliotheken, die Sie in Ihr Projekt aufnehmen." Gehen Sie mit C ++ , aber vermeiden erweiterte Funktionen, wie streams, string, new, virtualFunktionen etc. Überprüfen Sie alle Bibliotheksfunktion , bevor sie in den endgültigen Code zu lassen, weil der Größenbeschränkung (basierend auf dieser Antwort)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.