Warum dominiert C auf dem Markt für eingebettete Software? [geschlossen]

14

Fast jeder wird jetzt den Segen sagen:

leistung !

Okay, C erlaubt es, athletischen Code zu schreiben. Aber es gibt doch noch andere Sprachen, die das können! Und die Optimierungskraft moderner Compiler ist großartig. Hat C einige Vorteile, die keine andere Sprache hat? Oder es werden einfach keine flexibleren Instrumente in der Domäne benötigt?

Reben
quelle
1
FWIW, Arduino kann mit C # gesteuert werden: arduino.cc/playground/Interfacing/Csharp
FrustratedWithFormsDesigner
@Frustrated: Ja, aber das ist ein Beispiel, und die meisten Leute, die Geräte bauen, verwenden Arduino.
Ed S.
2
Siehe auch: stackoverflow.com/questions/812717/…
Steve Melnikoff
1
@ dan04, in den allermeisten Fällen war das eigentlich kein Problem. Eine 6DOF-Simulationsgruppe der Texas Instruments Defence Systems und der Electronics Group führte 1988 ein kleines Experiment durch. Bis dahin hatten sie alle ihre Simulationen in FORTRAN durchgeführt. Sie versuchten, einen in PASCAL zu schreiben, um zu sehen, wie schlimm es wehtun würde. Sie stellten fest, dass PASCAL ihnen einen kleinen Leistungseinbruch bescherte, die Erhöhung der Zuverlässigkeit und die einfache Fehlersuche machten dies jedoch mehr als wett. Sie fanden unverblümt, dass die strenge Typprüfung von PASCAL eine GUTE Sache war. (Und ja, sie haben Arrays gemacht.)
John R. Strohm

Antworten:

41

Fast jeder wird jetzt den Segen sagen:

Performance!

Das ist ein Teil davon; Die deterministische Ressourcennutzung ist bei Geräten mit begrenzten Ressourcen zunächst wichtig, es gibt jedoch auch andere Gründe.

  1. Direkter Zugriff auf Low-Level-Hardware-APIs.
  2. Sie können einen C-Compiler für die überwiegende Mehrheit dieser Geräte finden. Dies gilt meines Erachtens nicht für eine Hochsprache.
  3. C (die Laufzeit und Ihre generierte ausführbare Datei) ist "klein". Sie müssen nicht viele Dinge in das System laden, um den Code zum Laufen zu bringen.
  4. Die Hardware-API / Treiber werden wahrscheinlich in C oder C ++ geschrieben.
Ed S.
quelle
14
+1 Verfügbarkeit von Compilern. Damals, als wir alles in der Versammlung schrieben, waren die ersten Gen-Compiler ein Geschenk Gottes.
Christopher Bibbs
8
+1, ich denke, deterministische Ressourcennutzung ist einer der wichtigsten Gründe. Sie haben nicht viel Gedächtnis, um alle Arten von Müll in der Spülmaschine zu sammeln.
user281377
4
+1 auch für "deterministische Ressourcennutzung". Bei vielen eingebetteten Systemen schließt diese Anforderung sogar die Verwendung einer dynamischen Speicherzuweisung aus. Viele andere Sprachen hängen stark von der dynamischen Speicherzuweisung ab (selbst viele vorteilhafte Aspekte von C ++ benötigen dynamischen Speicher).
Michael Burr
2
Ich möchte noch einen Punkt hinzufügen, der sich eher als sozialer als als als technischer Grund herausstellt. Ich denke, dass eingebettete Softwareentwickler tendenziell viel konservativer und veränderungsresistenter sind als andere Entwickler. Abhängig von Ihrer Sichtweise kann dies eine gute oder eine schlechte Sache sein.
Michael Burr
1
Wenn ich als System-Typ spreche, bin ich misstrauisch gegenüber großen Abstraktionen. Sie sind großartig, bis sie aufhören zu arbeiten oder etwas Lustiges tun. In diesem Fall kann das Debuggen enorme Kopfschmerzen bereiten. Das ist nichts, was ich in einem Low-Level-System haben möchte.
Ed S.
18

C wurde entwickelt, um eine CPU zu modellieren, da C dafür geschaffen wurde, Unix plattformübergreifend portierbar zu machen, anstatt nur die Assemblersprache zu schreiben.

Dies bedeutet, dass C-Programme gut als Programmiersprache für Programme funktionieren, deren Abstraktionsebene sehr nahe an der tatsächlichen CPU liegen muss, was bei eingebetteter Hardware der Fall ist.

Hinweis: C wurde um 1970 entwickelt und die CPUs waren damals einfacher.


quelle
3
+1: Dies ist definitiv der Grund. Vielleicht haben die Leute versucht, neuere Hochsprachen zu entwerfen, die Funktionen moderner Prozessoren erfassen, aber niemand hat eine Sprache dafür entwickelt, die ansteckt.
Ken Bloom
2
@vines, C ist eine kleine Sprache mit einer großen Laufzeitbibliothek. All dies kann in der Laufzeitbibliothek durchgeführt werden. Es wird einfach nicht automatisch in die Standard-C-Bibliothek migriert, so dass es plattformspezifisch ist.
3
+1. C wurde für einen PDP-7 entwickelt und anfangs auf einem PDP-7 verwendet, der maximal 64 Kilowörter mit 18-Bit-Wörtern enthielt. Viel mehr "moderne" Sprachen haben größere Schwierigkeiten, sich in diese Art von Raum einzufügen. Besonders zum Schreiben eines Betriebssystems wie Unix.
greyfade
2
@greyfade: nicht so. UNIX entstand auf dem PDP-7, C jedoch nicht. Zitat aus dem Vorwort zu The C Programming Language : "C wurde ursprünglich von Dennis Ritchie für das UNIX-Betriebssystem DEC PDP-11 entwickelt und dort implementiert."
Jerry Coffin
1
@vines: Während es durchaus sinnvoll ist, eine direkte Unterstützung für das Threading in der Sprache in Betracht zu ziehen (vgl. Concurrent C), besteht ein wesentlicher Punkt eines Caches darin, dass die Dinge schneller werden, ohne dass der Programmierer oder die Sprache eingreifen müssen.
Jerry Coffin
11

Ein Grund für die Dominanz ist, dass es die richtigen Werkzeuge für die Aufgabe gibt. Nachdem ich Embedded-Plattformen sowohl in Java als auch in C / C ++ entwickelt habe, kann ich Ihnen sagen, dass der Ansatz von C ++ einfach natürlicher ist. Es ist ziemlich ärgerlich, dem Entwickler zu ersparen, dass er oder sie durch die Reifen springt, weil die Sprache zu hoch ist. Ein gutes Beispiel ist das Fehlen von vorzeichenlosen Variablen in Java.

Und die praktischen Funktionen von VM / interpretierten Sprachen sind normalerweise nicht realisierbar und werden bei der Implementierung nicht berücksichtigt, z. B. Garbage Collection.

Celebdor
quelle
3
"sowohl Java als auch C / C ++" - Ich hoffe, Sie meinten "alle drei: Java C und C ++", da C und C ++ verschiedene Sprachen sind.
BЈовић
1
@ BЈовић: Jahre später zu antworten, um zu bestätigen, dass ja, dass ich alle drei meinte. Ich benutzte beide nach dieser Definition: "Wird als Funktionswort verwendet, um die Einbeziehung von zwei oder mehr Dingen anzuzeigen und zu betonen" (zwei oder mehr Dinge) :-)
Celebdor
10

C benötigt an und für sich nur sehr wenig Laufzeitunterstützung, sodass der Overhead viel geringer ist. Sie müssen weder Speicherplatz noch Speicherplatz für die Laufzeitunterstützung aufwenden, noch Zeit und Mühe aufwenden, um diese Unterstützung zu minimieren, oder dies bei der Gestaltung Ihres Projekts berücksichtigen.

Geekosaurier
quelle
1
Kommt es wirklich nie vor, dass Sie diese Funktionalität brauchen und selbst neu erfinden? Beispielsweise sind mit switches erstellte große Zustandsautomaten schrecklich, und dieselben mit Klassenhierarchien erstellten Maschinen sind nett und wartbar.
Reben
1
@vines - Sie haben normalerweise einen definierten Satz von Eingaben, Zustandsautomaten, die auf Schaltern aufgebaut sind / wenn Leitern übersichtlicher und dokumentierbarer sind als eine Erbe der Magie "hinter den Kulissen", polymorphe Aufrufe.
Martin Beckett
2
@Martin: Für jemanden mit ein wenig Erfahrung in der OO-Entwicklung sind polymorphe Aufrufe weder "magisch" noch "hinter den Kulissen", und die Vorstellung, dass große switch / if-Anweisungen klarer und dokumentierbarer sind, erscheint geradezu bizarr.
Michael Borgwardt
3
Finde heraus, was passiert, wenn Pin27 hoch geht. Option 1: Suche nach "Fall PIN27:" Option 2: Verfolge einen Iterator über eine Karte von Funktoren, um herauszufinden, welches für ein PIN-Objekt aufgerufen wird, das zur Laufzeit Pin 27 zugewiesen ist. Das Problem mit vielen OO-Codes ist, dass die einzige Möglichkeit, sie zu lesen, darin besteht, sie im Wesentlichen auszuführen. Auf einer Plattform ohne Laufzeit-Debugging oder sogar einer Konsole, bei der der Code auf Papier oder im Kopf verfolgt wird.
Martin Beckett
2
Etwas tangential zu dieser Diskussion, gibt es einen Grund, warum Ladder Logic (eine noch primitivere Version von switch, könnte man sagen) immer noch in vielen eingebetteten Anwendungen verwendet wird. Einfacher zu debuggen, einfacher zu überprüfen.
Geekosaurier
9

Wie bereits in anderen Antworten erwähnt, wurde C in den frühen 1970er Jahren entwickelt, um die Assemblersprache einer Minicomputer-Architektur zu ersetzen. Damals kosteten diese Computer in der Regel Zehntausende von Dollar, einschließlich Speicher und Peripheriegeräte.

Heutzutage können Sie mit einem eingebetteten 16-Bit-Mikrocontroller die gleiche oder eine größere Computerleistung erzielen, die in Einzelmengen bis zu vier Dollar kostet - einschließlich integriertem RAM und E / A-Controllern. Ein 32-Bit-Mikrocontroller kostet vielleicht ein oder zwei Dollar mehr.

Wenn ich diese kleinen Leute programmiere, was ich in 90% der Fälle mache, wenn ich nicht die Boards entwerfe, auf denen sie sitzen, stelle ich mir gerne vor, was der Prozessor machen wird. Wenn ich in Assembler schnell genug programmieren könnte, würde ich das tun.

Ich möchte nicht alle Arten von Abstraktionsebenen. Ich debugge oft, indem ich durch eine Dissembler-Liste auf dem Bildschirm gehe. Das ist viel einfacher, wenn Sie das Programm zunächst in C geschrieben haben.

Tcrosley
quelle
1
Für einige eingebettete Anwendungen ist dieser "Dollar oder zwei mehr" sehr wichtig. Niemand wird die Preisauswirkungen auf sein Auto bemerken, aber auf seinen Thermostat oder CD-Player.
David Thornley
3
@ David Thornley, yep, stimme vollkommen zu, deshalb habe ich derzeit Projekte mit 8-, 16- und 32-Bit-Mikros zur gleichen Zeit für verschiedene Kunden. (Der Stromverbrauch ist ein weiterer Grund für kleinere Geräte.)
tcrosley
1
Der Preis wird weniger durch die Prozessorkosten als durch die Pinanzahl bestimmt. Boards sind viel teurer als Chips.
Yttrill
7

Es dominiert nicht ganz, da C ++ zunehmend verwendet wird, da sich die Compiler verbessert haben und die Hardwareleistung gestiegen ist. C ist jedoch aus einigen Gründen immer noch sehr beliebt.

  1. Breite Unterstützung. Nahezu jeder Chiphersteller stellt einen AC-Compiler zur Verfügung, und jeder Beispielcode und Treiber wird wahrscheinlich in c geschrieben. C ++ - Compiler sind immer häufiger anzutreffen, aber für einen bestimmten Chip kein totes Zertifikat, und sie sind häufig fehlerhafter. Sie wissen auch, dass jeder Embedded-Ingenieur in der Lage sein wird, in c zu arbeiten. Es ist die Verkehrssprache der Branche.

  2. Performance. Ja, du hast es gesagt. Die Leistung ist nach wie vor entscheidend, und in einer Umgebung, in der Kernroutinen noch häufig in Assembler geschrieben oder zumindest in Bezug auf die Assembly-Ausgabe in c optimiert werden, darf die Bedeutung dieser Funktion nicht unterschätzt werden. Eingebettete Ziele sind oft sehr kostengünstig und haben sehr kleine Speicher und wenige Mips.

  3. Größe. C ++ ist tendenziell größer. Sicherlich wird alles, was die STL verwendet, größer sein. Im Allgemeinen sowohl hinsichtlich der Programmgröße als auch des Speicherbedarfs.

  4. Konservatismus. Es ist eine sehr konservative Branche. Zum einen, weil die Ausfallkosten oft höher sind und das Debuggen oft weniger zugänglich ist, zum anderen, weil es nicht geändert werden muss. Für ein kleines eingebettetes Projekt macht c die Arbeit gut.

Luke Graham
quelle
11
Sehen Sie, es ist die Nummer 3, die einer der am weitesten verbreiteten Mythen über C ++ zu sein scheint. Schreiben Sie einen typsicheren Container für 5 verschiedene Typen in C, und Sie haben mindestens so viel "Aufblähen" verursacht, als wenn Sie einen einzelnen STL-Container für 5 verschiedene Typen verwenden würden. C-Programmierer umgehen dies, indem sie Container auf undurchsichtige Typen schreiben (void *). Der Vergleich mit einer AWL-Vorlage ist ein Kategoriefehler. Ich muss allerdings zugeben, dass es in der Tat einer der häufigsten "Gründe" ist, C.
Edward Strange am
Ich stimme voll und ganz zu, dass Sie, um die volle Funktionalität in c zu replizieren, den gleichen Footprint wie in c ++ haben. Der 'Vorteil' von c ist, dass Sie selektiv sein können. Bei jedem wichtigen Projekt würde ich lieber C ++ verwenden, aber manchmal ist die Zielhardware auf einen Punkt beschränkt, an dem dies nicht praktikabel ist. Trotzdem ist # 1 meiner Erfahrung nach der Hauptgrund.
Luke Graham
6

Bei eingebetteten Systemen ist die Leistung das Wichtigste . Aber wie Sie sagten, warum C und nicht irgendeine andere performante Sprache?

Viele Leute haben bisher die Verfügbarkeit von Compilern erwähnt , aber niemand hat die Verfügbarkeit von Entwicklern erwähnt . Viele Entwickler kennen C bereits als beispielsweise OCaml.

Das sind die drei Biggies.

BlueRaja - Danny Pflughoeft
quelle
6

Embedded Software ist ganz anders.

In einer Desktop-App sparen Sie durch Abstraktionen und Bibliotheken viel Entwicklungszeit. Sie haben den Luxus, ein paar Megabyte oder Gigabyte RAM oder einige 64-Bit-CPU-Kerne mit 2 + GHz auszugeben, und jemand anderes (Benutzer) bezahlt für diese Hardware. Möglicherweise wissen Sie nicht, auf welchen Systemen die App ausgeführt wird.

In einem eingebetteten Projekt sind die Ressourcen oft sehr begrenzt. In einem Projekt, an dem ich gearbeitet habe (Prozessoren der PIC 17X-Serie), verfügte die Hardware über 2 KB Programmspeicher, 8 Ebenen (in-Hardware) Stack und 192 Byte (<0,2 KB) RAM. Unterschiedliche E / A-Pins hatten unterschiedliche Funktionen, und Sie haben die Hardware nach Bedarf konfiguriert, indem Sie in Hardwareregister geschrieben haben. Das Debuggen umfasst ein Oszilloskop und einen Logikanalysator.

In eingebetteten Umgebungen stören Abstraktionen häufig und verwalten (und kosten) Ressourcen, die Sie nicht haben. ZB haben die meisten eingebetteten Systeme kein Dateisystem. Mikrowellenherde sind eingebettete Systeme. Kfz-Motorsteuerungen. Einige elektrische Zahnbürsten. Einige Kopfhörer mit Geräuschunterdrückung.

Ein sehr wichtiger Faktor für mich bei der Entwicklung eingebetteter Systeme ist die Kenntnis und Kontrolle darüber, in was der Code in Bezug auf Anweisungen, Ressourcen, Speicher und Ausführungszeit übersetzt wird. Oft steuert die genaue Reihenfolge der Anweisungen z. B. das Timing für die Wellenformen der Hardwareschnittstelle.

Abstraktionen und "Magie" hinter den Kulissen (z. B. ein Müllsammler) eignen sich hervorragend für Desktop-Apps. Garbage-Collectors ersparen Ihnen viel Zeit bei der Suche nach Speicherlecks, wenn Speicher dynamisch zugewiesen wird / werden kann.

In der Echtzeit-Embedded-Welt müssen wir jedoch wissen und steuern, wie lange die Dinge dauern, manchmal bis zu Nanosekunden, und können kein weiteres paar Megabyte RAM oder eine schnellere CPU für ein Problem ausgeben. Ein einfaches Beispiel: Beim Software-Dimmen von LEDs durch Steuern des Arbeitszyklus (die CPU hatte nur die Ein- / Aus-Steuerung der LEDs) ist es NICHT in Ordnung, dass der Prozessor ausgeht und z. B. eine Speicherbereinigung für 100 ms durchführt, da die Anzeige sichtbar wäre Blitz hell oder erlöschen.

Ein hypothetischeres Beispiel ist eine Motorsteuerung, die Zündkerzen direkt zündet. Wenn diese CPU abschaltet und 50 ms lang Müll sammelt, wird der Motor für einen Moment ausgeschaltet oder an der falschen Kurbelwellenposition gezündet, wodurch der Motor möglicherweise abgewürgt wird (während er vorbeifährt?) Oder mechanisch beschädigt wird. Sie könnten jemanden töten lassen.

Technophile
quelle
Das ist genauso wahr wie für C irrelevant - das Problem, auf das Sie sich beziehen, ist nur das Verhalten des GC ... C ++ hat keine GCs und weißt du was? Ich persönlich benutze es wegen der Zeilen-Kommentare und der strengeren Typensicherheit =)
Reben