Wird C # teilweise interpretiert oder wirklich kompiliert?

74

Es gibt viele widersprüchliche Informationen dazu. Während einige sagen, dass C # kompiliert wird (da es in IL und dann in nativen Code kompiliert wird, wenn es ausgeführt wird), sagen andere, dass es so interpretiert wird, dass es .NET benötigt. EN Wiki sagt:

Viele interpretierte Sprachen werden zuerst zu einer Form von Code für virtuelle Maschinen kompiliert, der dann entweder interpretiert oder zur Laufzeit zu nativem Code kompiliert wird.

Ich bin also ziemlich verwirrt. Könnte jemand dies klar erklären?

John V.
quelle
1
Mögliches Duplikat von Wird C # interpretiert oder kompiliert?
Cody Gray
Inb4 erfindet jemand eine Sprache, die als LLVM-IR verbreitet wird, und erfordert, dass Benutzer eine eigenständige Instanz von LLVM installieren.
SOFe

Antworten:

74

C # wird vom c # -Compiler in IL kompiliert.

Diese IL wird dann bei Bedarf Just-in-Time (JIT) in die native Assemblersprache des Hostcomputers kompiliert. Es wäre jedoch möglich, eine .NET-Laufzeit zu schreiben, die stattdessen die IL interpretiert. Selbst wenn dies getan würde, würde ich immer noch argumentieren, dass c # eine kompilierte Sprache ist.

Simon
quelle
4
Aber warum wird es dann von vielen Programmierern als interpretierte Sprache angesehen?
John V
16
Persönlich habe ich noch nie jemanden gehört, der C # als interpretierte Sprache bezeichnet.
Jrummell
8
Vielleicht irren sie sich einfach oder sind falsch informiert. Oder vielleicht irre ich mich :-)
Simon
21
JIT-Zusammenstellung! = Interpretiert
Spender
3
@JoSmo csc.exe ist das Befehlszeilenprogramm, mit dem c # erstellt wird. Es steht für C-Sharp Compiler
Simon
43

Eine rein kompilierte Sprache hat einige Vorteile. Geschwindigkeit in der Regel und häufig funktionierende Satzgröße. Eine rein interpretierte Sprache hat einige Vorteile. Flexibilität, keine explizite Kompilierungsphase zu benötigen, die es uns ermöglicht, vor Ort zu bearbeiten, und häufig einfachere Portabilität.

Eine jitted Sprache passt in diesem Fall in einen Mittelweg.

Dies ist allein ein Grund, warum wir uns eine Jitted-Sprache entweder als kompiliert oder als interpretiert vorstellen können, je nachdem, welche Position auf welcher Metrik wir erreichen möchten und welche Vorurteile wir für und gegen die eine oder andere haben.

C # kann auch beim ersten Ausführen kompiliert werden, wie dies in ASP.NET der Fall ist, wodurch es in diesem Fall nahezu interpretiert wird (obwohl es in diesem Fall immer noch in IL kompiliert und dann jitted wird). Sicherlich hat es so ziemlich alle Vorteile der Interpretation in diesem Fall (vergleiche mit VBScript oder JScript, die im klassischen ASP verwendet werden), zusammen mit vielen Vorteilen der Kompilierung.

Streng genommen wird keine Sprache als Sprache geschrieben, interpretiert oder kompiliert. Wir können C # in nativen Code einbinden (wenn es jedoch so etwas wie das dynamische Laden einer Assembly ausführt, werden weiterhin IL und Jitting verwendet). Wir könnten einen Interpreter für C oder C ++ schreiben (mehrere Leute haben dies getan). In seinem häufigsten Anwendungsfall wird C # jedoch zu IL kompiliert, das dann jitted wird, was nicht ganz die klassische Definition von interpretiert oder kompiliert ist.

Jon Hanna
quelle
Ich stimme zu no language is jitted, interpretted or compiled qua language. Ich habe ein bisschen über Python gesehen, das zuerst kompiliert wird byteCodeund dann zur Laufzeit byteCodevom Interpreter des jeweiligen Betriebssystems interpretiert wird. Diese Tatsache trug nur zu meinem Erstaunen bei, das durch die Definitionen kompilierter, jitted und interpretierter Sprachen verursacht wurde.
RBT
JIT-Sprachen können schneller als native sein. Sie wissen, dass Instrumentation gcc hat, wo es beim Ausführen eine Leistungsmessdatei ausgibt und diese dann in gcc zurückspeist, um eine optimierte Binärdatei zu kompilieren? JVM und CLR machen das beide kontinuierlich.
John Moser
18

Zu viele Semantiken und Aussagen basieren auf Meinungen.

Zunächst einmal: C # ist keine interpretierte Sprache. Die CLR und die JVM werden als "Laufzeiten" oder "Middleware" betrachtet, aber der gleiche Name gilt für Dinge wie Perl. Dies schafft viel Verwirrung bei Menschen, die sich mit Namen befassen.

Der Begriff "Interpreter", der sich auf eine Laufzeit bezieht, bedeutet im Allgemeinen, dass vorhandener Code nicht nativen Code interpretiert. Es gibt zwei große Paradigmen: Das Parsen liest den Rohquellcode und ergreift logische Aktionen. Die Bytecode-Ausführung kompiliert den Code zunächst zu einer nicht nativen Binärdarstellung, für deren Interpretation viel weniger CPU-Zyklen erforderlich sind.

Java wurde ursprünglich zu Bytecode kompiliert und durchlief dann einen Interpreter. Jetzt liest die JVM den Bytecode und kompiliert ihn just-in-time zu nativem Code. CIL macht dasselbe: Die CLR verwendet die Just-in-Time-Kompilierung für nativen Code.

Berücksichtigen Sie alle Kombinationen aus dem Ausführen von Quellcode, dem Ausführen von Bytecode, dem Kompilieren in native Just-in-Time-Kompilierung, dem Ausführen von Quellcode über einen Compiler in Just-in-Time-Native usw. Die Semantik, ob eine Sprache kompiliert oder interpretiert wird, wird bedeutungslos.

Als Beispiel: Viele interpretierte Sprachen verwenden die Just-in-Time-Bytecode-Kompilierung. C # wird zu CIL kompiliert, das JIT zu native kompiliert. Im Gegensatz dazu kompiliert Perl sofort ein Skript zu einem Bytecode und führt diesen Bytecode dann über einen Interpreter aus. Sie können eine C # -Baugruppe nur im CIL-Bytecode-Format ausführen. Sie können ein Perl-Skript nur im Rohquellcode-Format ausführen.

Just-in-Time-Compiler führen auch viele externe und interne Instrumente aus. Die Laufzeit verfolgt die Ausführung verschiedener Funktionen und passt dann das Codelayout an, um Zweige und Codeorganisation für den jeweiligen Ausführungsfluss zu optimieren. Dies bedeutet, dass JIT-Code schneller ausgeführt werden kann als nativ kompilierter Code (wie C ++ normalerweise ist oder wie C # über IL2CPP ausgeführt wird), da die JIT ihre Optimierungsstrategie während der Ausführung an den tatsächlichen Ausführungsfall des Codes anpasst.

Willkommen in der Welt der Computerprogrammierung. Wir haben uns entschlossen, es extrem kompliziert zu machen und dann alles mit unbeschreiblichen Namen zu versehen. Der Zweck ist es, Flammenkriege über die Definition von Wörtern zu erzeugen, die keine praktische Bedeutung haben.

John Moser
quelle
JVM interpretiert den Bytecode und kompiliert dann einige der Methoden / Schleifenkörper zu nativem Code. Diese Kompilierung kann parallel zur Bytecode-Interpretation erfolgen und der Code kann im laufenden Betrieb ausgetauscht werden.
Steves
Ich kann kein Zitat dafür finden. Nach meinem Verständnis interpretiert die JVM den Bytecode so, wie er von JIT ausgeführt wird. Wenn sie also auf Bytecode stößt, den sie während des aktuellen Laufs noch nicht behandelt hat, führt sie ihn durch die JIT aus und führt den resultierenden nativen Codeblock aus. JIT-and-Execute ist billiger als die Interpretation von Bytecodes, und die Implementierung beider Systeme ist sehr komplex.
John Moser
Kasse zB slidehare.net/ZeroTurnaround/… . Was Sie beschreiben, ist das, was .NET tut. Was ich beschrieben habe ist, was zB Hotspot JVM macht und ja, es ist ziemlich komplex, deshalb wurde es für eine Weile entwickelt. Sie müssen den Code per Bytecode interpretieren, um Profilinformationen zu erhalten (denken Sie daran: Wenn die Verzweigung die meiste Zeit verwendet wurde usw.), die dann im optimierenden Compiler verwendet werden (dies, wenn die Verzweigung nie verwendet wurde, geben Sie nicht zu viel aus Ressourcen zur Optimierung).
Steves
1
Eigentlich ist Perl jetzt auch jitted.
Erik Aronesty
Sie können die Profilerstellung in nativen Code instrumentieren. gcc verfügt über Profiling-Tools als solche. Der Compiler kann einen Schleifeniterator identifizieren und Code hinzufügen, um seine Eingangs- und Ausgangszustände zu vergleichen. es kann eine Variable setzen, wenn ein Zweig genommen wird; und so weiter. Dies kann dazu führen, dass die Anzahl der Anrufe, die Anzahl der Schleifen, die Anzahl der Verzweigungen usw. zwischen jeder Überprüfung der Profildaten durch die JIT summiert werden. Es kostet ein paar Zyklen - nicht annähernd so viel wie das Interpretieren von Bytecode.
John Moser
14

Wenn Sie das Gefühl haben, gelernt haben oder altmodisch sind, dass eine kompilierte EXE-Datei vom Quellcode zum Maschinencode wechselt, wird C # interpretiert. Wenn Sie der Meinung sind, dass kompiliert bedeutet, Quellcode in anderen Code wie Bytecode umzuwandeln, wird er konvertiert. Für mich wird alles interpretiert, was Laufzeitverarbeitung benötigt, um in dem Betriebssystem zu funktionieren, für das es erstellt wurde.

ChicagoBob
quelle
2
Wir fragen nicht nach einer Meinung und "für mich" ist eine Meinung. Dies ist kein Forum.
Angelo Mascaro
5
Leider ist die Art der Frage ist eine Meinung.
Erik Aronesty
13

Schauen Sie hier: http://msdn.microsoft.com/library/z1zx9t92

In C # geschriebener Quellcode wird in eine Zwischensprache (IL) kompiliert, die der CLI-Spezifikation entspricht.

(...)

Wenn das C # -Programm ausgeführt wird, wird die Assembly in die CLR geladen, die basierend auf den Informationen im Manifest verschiedene Aktionen ausführen kann. Wenn die Sicherheitsanforderungen erfüllt sind, führt die CLR eine Just-in-Time-Kompilierung (JIT) durch, um den IL-Code in native Maschinenanweisungen zu konvertieren.

psur
quelle
Vielen Dank. Wenn ich das richtig verstehe, kann die Verwechslung mit Interpretationen von der benötigten virtuellen Maschine (CRM) herrühren, ist jedoch kein echter Interpret.
John V
6

Lassen Sie uns zunächst die Definitionen von interpretiert und kompiliert verstehen.

"Kompilieren" (wenn auf Code Bezug genommen wird) bedeutet, Code von einer Sprache in eine andere zu übersetzen. In der Regel vom lesbaren Quellcode in den Maschinencode, den der Zielprozessor ... verarbeiten kann.

"Interpretieren" (wenn auf Code Bezug genommen wird) bedeutet AUCH, Code von einer Sprache in eine andere zu übersetzen. Dieses Mal wird es jedoch normalerweise verwendet, um vom lesbaren Quellcode in einen Zwischencode überzugehen, der von einer virtuellen Maschine verwendet wird, die ihn in Maschinencode interpretiert.

Nur um klar zu sein
Quellcode -> Compiler -> Maschinencode Quellcode
-> Compiler -> Bytecode -> Interpreter -> Maschinencode

Jede Sprache kann theoretisch interpretiert oder zusammengestellt werden . In der Regel wird Java in Bytecode kompiliert, der von der Java Virtual Machine in Maschinencode interpretiert wird. C # wird normalerweise in Bytecode interpretiert, der von der CLR, der Common Language Runtime, einer anderen virtuellen Maschine kompiliert wird.

Bei weitem ist das Ganze ein Marketing-Gimmick. Der Begriff "interpretiert" wurde hinzugefügt (oder zumindest in der Verwendung erhöht), um zu veranschaulichen, wie ordentlich das Just-in-Time-Kompilieren war. Aber sie hätten einfach "kompiliert" verwenden können. Die Unterscheidung ist eher eine Untersuchung der englischen Sprache und der Geschäftstrends als etwas Technisches.

Philip
quelle
7
In einem Interpreter wird zur Laufzeit kein Maschinencode generiert, sondern nur vorhandener Maschinencode ausgeführt. Nach diesem Standard ist es völlig falsch, die Common Language Runtime als Interpreter zu bezeichnen.
Ben Voigt
3

C # wird in seiner Lebensdauer sowohl interpretiert als auch kompiliert. C # wird in eine virtuelle Sprache kompiliert, die von einer VM interpretiert wird.

Die Verwirrung ergibt sich aus dem unscharfen Konzept einer "kompilierten Sprache".

"Kompilierte Sprache" ist in gewissem Sinne eine Fehlbezeichnung, da kompiliert oder interpretiert keine Eigenschaft der Sprache, sondern der Laufzeit ist.

Beispiel: Sie könnten einen C-Interpreter schreiben, aber die Leute nennen ihn normalerweise eine "kompilierte Sprache", da C-Implementierungen zu Maschinencode kompiliert werden und die Sprache unter Berücksichtigung der Kompilierung entwickelt wurde.

Ajfabbri
quelle
3
Nein, die Desktop-.NET-VM (Common Language Runtime) verfügt über einen JIT-Compiler und keinen Interpreter. Im Gegensatz dazu interpretiert das .NET-Mikroframework, das auf winzigen eingebetteten Geräten zu finden ist, die möglicherweise nicht einmal die Änderung des Laufzeitcodes unterstützen, die IL tatsächlich.
Ben Voigt
Quelle -> (Compiler) -> Intermediate Language -> (Interpreter) -> Native Code. Ich betrachte JIT als Interpreter-Optimierung. Es ist im Grunde "Caching" auf der Interpreter-Ebene. Sie können beide Schritt-Compiler aufrufen, wenn Sie möchten.
Ajfabbri
2

Die meisten Sprachen, wenn nicht alle, benötigen einen Interpreter, der ihre Skripte in Maschinencodes übersetzt, damit die CPU sie verstehen und ausführen kann!

Jede Sprache behandelt den Übersetzungsprozess anders!

Zum Beispiel ist "AutoIt" ​​eine 100% interpretierte Sprache!

Warum?

Weil der "AutoIt" ​​-Interpreter ständig benötigt wird, während sein Skript ausgeführt wird! Siehe Beispiel unten:

Loop, 1000
Any-Code

Der "AutoIt" ​​-Interpreter müsste "Any-Code" 1000 Mal in Maschinencode übersetzen, was "AutoIt" ​​automatisch zu einer langsamen Sprache macht!

Andererseits behandelt C # den Übersetzungsprozess anders, der Interpreter von C # wird nur einmal vor der Skriptausführung benötigt, danach wird er während der Skriptausführung nicht mehr benötigt!

Der Interpreter von C # müsste "Any-Code" nur einmal in Maschinencode übersetzen, was "C #" automatisch zu einer schnellen Sprache macht!

Also im Wesentlichen,

  • Eine Sprache, die ihren Interpreter während der Skriptausführung benötigt, ist eine "interpretierte Sprache"!

  • Eine Sprache, deren Interpreter nur einmal benötigt wird (vor der Skriptausführung), ist eine "kompilierte Sprache"!

Schließlich,

  • "AutoIt" ​​ist eine "interpretierte Sprache"!

  • "C #" ist eine "kompilierte Sprache"!

Nutzer
quelle
1

Ich glaube, das ist ein ziemlich altes Thema.

Aus meiner Sicht durchläuft der interpretierte Code einen Interpreter, wird zeilenweise übersetzt und gleichzeitig ausgeführt. Wie bei Beispiel-Javascript handelt es sich um einen interpretierten Code. Wenn in einer Javascript-Zeile ein Fehler auftritt, wird das Skript nur unterbrochen.

Während des kompilierten Codes wird ein Compiler durchlaufen und der gesamte Code sofort in eine andere Codeform übersetzt, ohne ihn zuerst auszuführen. Die Ausführung erfolgt in einem anderen Kontext.

Jonny
quelle
JavaScript wird entweder sofort wie C # JIT-kompiliert oder genauso ausgeführt wie HotSpot JVM, interpretiert, bis Teile des Codes heiß werden. Zu diesem Zeitpunkt wird es über einen optimierenden Compiler JIT-kompiliert. Dies hängt von der JavaScript-Engine ab. JavaScript wurde seit mehr als 10 Jahren nicht mehr interpretiert.
Julian Jensen
0

C # verfügt wie Java über einen Hybrid-Sprachprozessor. Hybridprozessoren übernehmen sowohl die Interpretation als auch die Kompilierung.

P.Brian.Mackey
quelle
0

Da ein Computer nur Binärcode ausführen kann, führt jede Sprache an der einen oder anderen Stelle zur Erzeugung von Binärcode. Die Frage ist: Können Sie mit der Sprache ein Programm im Binärcode erstellen? Wenn ja, dann ist es eine kompilierte Sprache: Per Definition bezieht sich "kompiliert" in "kompilierte Sprache" auf die Kompilierung in Binärcode, nicht auf die Umwandlung in einen Zwischencode. Wenn die Sprache zur Erstellung eines solchen Zwischencodes für ein Programm führt, benötigt sie eine zusätzliche Software, um die binäre Kompilierung aus diesem Code durchzuführen: Es handelt sich dann um eine interpretierte Sprache. Ist ein von C # "kompiliertes" Programm direkt auf einem Computer ausführbar, ohne dass auf diesem Computer eine andere Software installiert ist? Wenn nein, dann ist es eine interpretierte Sprache. Für eine interpretierte Sprache Es ist ein Interpreter, der den zugrunde liegenden Binärcode meistens auf dynamische Weise generiert, da dieser Mechanismus die Grundlage für die Flexibilität solcher Sprachen ist. rem. : Manchmal sieht es nicht offensichtlich aus, weil der Interpreter im Betriebssystem gebündelt ist

Klarer Kopf
quelle
Nach dieser Definition war QBasic ein Compiler. Das ist eindeutig ein Topf. C # ist auch eine interpretierte Sprache, mit einigen JITting hier und da als Optimierung. Natürlich können Sie auch NGen .Net IL verwenden, aber Sie verlieren die Optimierung, die der JITter ausführen kann. Was Sie in IL erhalten, ist eine Liste von Daten, die zum Versenden von Anrufen in Unterroutinen verwendet werden. Es wird kein Maschinencode generiert oder ausgeführt, es sei denn, die Laufzeit wird stark genutzt und die Läufe der P-Code-Daten werden durch JITted-Maschinencode ersetzt, um das Versenden von Anrufen zu ersetzen.
Bob77
0

Wenn wir mit der Definition des Dolmetschers einverstanden sind « In der Informatik ist ein Dolmetscher ein Computerprogramm, das Anweisungen, die in einer Programmier- oder Skriptsprache geschrieben sind, direkt ausführt, dh ausführt, ohne dass sie zuvor in ein Maschinensprachenprogramm kompiliert worden sein müssen. »Es besteht kein Zweifel: C # ist keine interpretierte Sprache.

Dolmetscher auf Wikipedia

Angelo Mascaro
quelle
0

C # ist eine kompilierbare Sprache.

Wahrscheinlich, weil ich auch diese Art von Meinungen getroffen habe, ist die Tatsache, dass jemand denkt, dass es einen Dolmetscher für C # -Sprache gibt, auf die Art von Projekten wie zurückzuführen

C # Interpreter Console

oder zum Beispiel berühmt

LinqPAD

Hier können Sie nur Zeilen des Codes schreiben und ausführen, was den Eindruck erweckt, dass es sich um eine Python- ähnliche Sprache handelt, die nicht wahr ist . Es kompiliert diese Zeilen und führt sie wie eine gewöhnliche kompilierbare Programmiersprache aus (aus Sicht des Workflows).

Tigran
quelle
1
Vielen Dank. Dennoch wären C ++ und C # unter diesem Gesichtspunkt beide kompilierte Sprachen. Aber ich denke, es ist nicht so klar wie bei C ++, es wird direkt zu nativem Code kompiliert, während es bei .NET nur CIL ist.
John V
1
C # wird, wie hier beantwortet, zuerst in die Zwischensprache und erst nach der Kompilierung in maschinenspezifischem Maschinencode kompiliert. Es gibt einen Grund, warum Eric Lippert die Antwort stackoverflow.com/questions/7875253/… überprüft , um die Gründe dafür zu verstehen.
Tigran