Kurze Antwort? Manchmal.
Technisch gesehen hat jede Abstraktion ihren Preis, und eine Programmiersprache ist eine Abstraktion davon, wie die CPU funktioniert. C ist jedoch sehr nahe dran. Ich erinnere mich, dass ich vor Jahren laut lachen musste, als ich mich bei meinem UNIX-Konto anmeldete und die folgende Glücksnachricht erhielt (als solche Dinge noch populär waren):
Die Programmiersprache C -- A Sprache, die die Flexibilität der Assemblersprache mit mit der Leistungsfähigkeit der Assemblersprache.
Es ist lustig, weil es wahr ist: C ist wie ein portabler Assembler.
Es ist erwähnenswert, dass Assemblersprache einfach läuft, egal wie man sie schreibt. Es gibt jedoch einen Compiler zwischen C und der Assemblersprache, die er erzeugt, und das ist extrem wichtig, weil Wie schnell Ihr C-Code ist, hat sehr viel damit zu tun, wie gut Ihr Compiler ist.
Als der gcc auf den Markt kam, war er unter anderem deshalb so beliebt, weil er oft so viel besser war als die C-Compiler, die mit vielen kommerziellen UNIX-Varianten ausgeliefert wurden. Er war nicht nur ANSI C (nichts von diesem K&R C-Müll), sondern auch robuster und produzierte in der Regel besseren (schnelleren) Code. Nicht immer, aber oft.
Ich sage Ihnen das alles, weil es keine pauschale Regel über die Geschwindigkeit von C und Assembler gibt, weil es keinen objektiven Standard für C gibt.
Auch bei Assembler gibt es große Unterschiede, je nachdem, welchen Prozessor Sie verwenden, wie Ihr System beschaffen ist, welchen Befehlssatz Sie benutzen und so weiter. Historisch gesehen gab es zwei CPU-Architekturfamilien: CISC und RISC. Der größte Akteur im Bereich CISC war und ist die x86-Architektur (und der Befehlssatz) von Intel. RISC dominierte die UNIX-Welt (MIPS6000, Alpha, Sparc und so weiter). CISC hat den Kampf um die Herzen und Köpfe der Menschen gewonnen.
Wie auch immer, als ich ein jüngerer Entwickler war, lautete die gängige Meinung, dass handgeschriebene x86-Programme oft viel schneller sind als C, weil die Architektur so komplex ist, dass es von Vorteil ist, wenn ein Mensch sie ausführt. RISC hingegen schien für Compiler konzipiert zu sein, so dass niemand (den ich kannte) einen Sparc-Assembler schrieb. Ich bin mir sicher, dass es solche Leute gab, aber zweifelsohne sind sie inzwischen beide verrückt geworden und institutionalisiert worden.
Die Befehlssätze sind ein wichtiger Punkt, selbst in ein und derselben Prozessorfamilie. Bestimmte Intel-Prozessoren haben Erweiterungen wie SSE bis SSE4. AMD hatte seine eigenen SIMD-Befehle. Der Vorteil einer Programmiersprache wie C bestand darin, dass jemand seine Bibliothek so schreiben konnte, dass sie für den jeweiligen Prozessor optimiert war, auf dem sie lief. In Assembler war das harte Arbeit.
Es gibt immer noch Optimierungen, die man in Assembler machen kann, die kein Compiler machen könnte, und ein gut geschriebener Assembler-Algorithmus wird genauso schnell oder schneller sein als sein C-Äquivalent. Die größere Frage ist: ist es das wert?
Letztendlich war Assembler jedoch ein Produkt seiner Zeit und wurde zu einer Zeit populärer, als CPU-Zyklen teuer waren. Heutzutage kann eine CPU, die in der Herstellung 5-10 $ kostet (Intel Atom), so ziemlich alles tun, was man sich wünschen kann. Der einzige wirkliche Grund, heutzutage Assembler zu schreiben, ist für Low-Level-Sachen wie einige Teile eines Betriebssystems (auch wenn der Großteil des Linux-Kernels in C geschrieben ist), Gerätetreiber, möglicherweise eingebettete Geräte (obwohl C auch dort dominiert) und so weiter. Oder einfach nur so zum Spaß (was etwas masochistisch ist).
0 Stimmen
Und nun wäre eine weitere Frage angebracht: Wann ist die Tatsache, dass Assembler schneller ist als C, tatsächlich von Bedeutung?
20 Stimmen
Eigentlich ist es recht trivial, kompilierten Code zu verbessern. Jeder, der über solide Kenntnisse in Assembler und C verfügt, kann dies erkennen, indem er den erzeugten Code untersucht. Eine einfache Möglichkeit ist die erste Leistungsklippe, von der man herunterfällt, wenn man in der kompilierten Version keine freien Register mehr hat. Im Durchschnitt wird der Compiler bei einem großen Projekt weitaus besser abschneiden als ein Mensch, aber es ist nicht schwer, bei einem Projekt von angemessener Größe Leistungsprobleme im kompilierten Code zu finden.
19 Stimmen
Die kurze Antwort lautet eigentlich: Assembler ist siempre Der Grund dafür ist, dass man Assembler ohne C haben kann, aber man kann C nicht ohne Assembler haben (in der binären Form, die wir früher "Maschinencode" nannten). Das heißt, die lange Antwort ist: C-Compiler sind ziemlich gut darin, zu optimieren und über Dinge "nachzudenken", an die man normalerweise nicht denkt, also hängt es wirklich von Ihren Fähigkeiten ab, aber normalerweise können Sie den C-Compiler immer schlagen; es ist immer noch nur eine Software, die nicht denken und Ideen bekommen kann. Sie können auch portablen Assembler schreiben, wenn Sie Makros verwenden und geduldig sind.
13 Stimmen
Ich bin ganz und gar nicht der Meinung, dass Antworten auf diese Frage "meinungsbasiert" sein müssen - sie können durchaus objektiv sein - es ist nicht so, als würde man versuchen, die Leistung der Lieblingssprachen zu vergleichen, für die jede von ihnen Stärken und Schwächen hat. Hier geht es darum, zu verstehen, wie weit uns Compiler bringen können und ab welchem Punkt es besser ist, sie zu übernehmen.
0 Stimmen
Es ist nicht einmal immer der Fall, dass Sie etwas in Assembler umschreiben müssen, um die Vorteile der Assembler-Kenntnisse zu nutzen. Wenn Sie Ihren C-Algorithmus einfach in verschiedenen Formen neu kompilieren und die vom Compiler erzeugte Assemblerdatei beobachten, können Sie effizienteren Code in C schreiben.
0 Stimmen
Ein esoterisches Beispiel: Suchen Sie im Internet nach
pclmulqdq crc
. pclmulqdq ist eine spezielle Assembler-Anweisung. Die optimierten Beispiele benötigen etwa 500 Zeilen Assemblercode. Einige X86 haben auch einencrc32c
Anweisung für einen bestimmten Fall von crc32. Benchmark-Ergebnisse für die Erzeugung von crc32 über ein 256MB (256*1024*1024) Byte-Array: c-Code mit Tabelle => 0,516749 sec, Assembler mit pcmuldq => 0,0783919 sec, c-Code mit crc32 intrinsic => 0,0541801 sec.30 Stimmen
Zu Beginn meiner beruflichen Laufbahn habe ich in einer Softwarefirma viel in C und Mainframe-Assembler geschrieben. Einer meiner Kollegen war, wie ich es nennen würde, ein "Assembler-Purist" (alles musste in Assembler sein), also wettete ich mit ihm, dass ich eine bestimmte Routine schreiben könnte, die in C schneller lief als das, was er in Assembler schreiben konnte. Ich habe gewonnen. Nachdem ich gewonnen hatte, sagte ich ihm, ich wolle eine zweite Wette abschließen - dass ich etwas in Assembler schneller schreiben könne als das C-Programm, das ihn bei der ersten Wette geschlagen hatte. Auch diese Wette habe ich gewonnen, was beweist, dass es mehr auf die Fähigkeiten des Programmierers ankommt als auf alles andere.
0 Stimmen
@ValerieR Nun, Sie haben auch bewiesen, dass Ihr Assemblerprogramm schneller war als Ihr C-Programm :-) Vielleicht könnte man sagen, dass Sie unabhängig von Ihrem Kenntnisstand in der C-Programmierung wahrscheinlich ein Assembler-Programm schreiben können, das schneller ist?
1 Stimmen
@RobertF: Wir lassen bei diesen Fragen oft den Teil "zu welchem Preis" weg. Ich kann schnelles C oder Assembler schreiben - manchmal ist das C billiger zu schreiben, und manchmal ist der Assembler billiger zu schreiben. Geschwindigkeit kommt oft von zwei Seiten: bessere Algorithmen oder Ausnutzung der Low-Level-Infrastruktur - Quicksort in C wird typischerweise schneller sein als Bubble Sort in Assembler. Aber wenn Sie identische Logik in beiden implementieren, bietet Ihnen der Assembler normalerweise Möglichkeiten, die Maschinenarchitektur besser auszunutzen als der Compiler - der Compiler ist universell einsetzbar, und Sie erstellen eine spezifische Anpassung für einen einzigen Anwendungsfall.
0 Stimmen
Ich habe mehrere M68000-Ersetzungen für C-Funktionen (memset, snprintf usw.) geschrieben, die erheblich schneller (und immer noch sicherer) als ihre C-Pendants sind. Ich habe auch Testcode geschrieben, um zu überprüfen, dass es a) funktioniert und b) tatsächlich schneller ist.