Der Unterschied zwischen einem Compiler und einem Interpreter
On Dezember 31, 2021 by adminDer Unterschied zwischen einem Compiler und einem Interpreter scheint nach der Definition klar zu sein:
- Ein Interpreter ist ein Programm, das Anweisungen, die in einer Programmiersprache geschrieben sind, direkt ausführt
- Ein Compiler ist ein Programm, das Quellcode in einer Low(er)-Level-Sprache umwandelt
Wenn man jedoch tiefer gräbt, findet man einige Verwischungen zwischen den beiden.
In der Tat könnte ein Interpreter die Ausgangssprache in eine Zwischenform übersetzen, um die Ausführung zu beschleunigen. Das ist das, was normalerweise bei einer Sprache passiert, die auf einer virtuellen Maschine basiert. Das führt natürlich zu einigen Fragen:
Sind alle Sprachen, die eine virtuelle Maschine verwenden, interpretiert?
Sind sie eigentlich alle kompiliert?
Man könnte beides sagen: eine Sprache wird zuerst in eine Zwischenform/Sprache kompiliert und dann wird dieses Zwischenprodukt zur Laufzeit interpretiert. Was auch zu einem weiteren Problem führt: ein Compiler und ein Interpreter sollten nicht als ein Programm betrachtet werden, sondern eher als eine Gruppe von Programmen, ein System. Was Sie als Benutzer für einen Compiler halten, kann in Wirklichkeit mehr als ein Programm umfassen. Es kann zum Beispiel einen Linker enthalten: ein Programm, das verschiedene Objektdateien in einer Datei zusammenfasst, damit sie leichter verwendet werden kann. Ähnliches könnte man von einem Interpreter sagen.
Können Sie mir alles über Compiler & Interpreter erzählen?
Also, aus welchen Teilen besteht ein Compiler oder ein Interpreter? Eine präzise und technische Antwort auf solche Fragen kann man in der Wissenschaft suchen. Oder man findet Diskussionen zu diesen Themen auf StackOverflow.
Was uns als Entwickler oder sogar als Schöpfer einer Sprache wirklich interessiert, ist, was die Unterschiede bei der Arbeit mit ihnen sind. Beide haben Vor- und Nachteile, und in der Tat können einige Sprachen sowohl einen Interpreter als auch einen Compiler haben, oder mehr als einen. Das werden wir sehen.
Der Hauptpunkt bleibt bestehen: ein Interpreter führt den Code jetzt aus, ein Compiler bereitet den Quellcode für eine spätere Ausführung vor. Alle praktischen Unterschiede ergeben sich aus diesen unterschiedlichen Zielen.
Wie verteilt man ein Programm
In der Praxis besteht ein wichtiger Unterschied darin, dass ein Compiler ein eigenständiges Programm erzeugt, während ein interpretiertes Programm immer den Interpreter benötigt, um zu laufen.
Wenn man ein kompiliertes Programm hat, kann man es ausführen, ohne etwas anderes installieren zu müssen. Das vereinfacht die Verteilung. Andererseits funktioniert die ausführbare Datei nur auf einer bestimmten Plattform: verschiedene Betriebssysteme und verschiedene Prozessoren benötigen verschiedene kompilierte Versionen. Ein kompiliertes C++-Programm könnte zum Beispiel auf einem Computer mit einem x86-Prozessor funktionieren, aber nicht auf einem mit einem ARM-Chip. Oder es könnte auf einem Linux-System funktionieren, aber nicht auf einem Windows-System.
Wenn Sie ein Programm interpretieren, können Sie die gleiche Kopie an Benutzer auf verschiedenen Plattformen verteilen. Allerdings benötigen sie einen Interpreter, der auf ihrer spezifischen Plattform läuft. Sie können entweder den ursprünglichen Quellcode oder eine Zwischenform weitergeben. Ein Interpreter lässt sich intuitiv folgendermaßen betrachten: Er ist wie die eval
-Funktion in JavaScript. Sie funktioniert überall dort, wo JavaScript funktioniert, aber sie braucht einen JavaScript-Interpreter für diese Plattform, um zu laufen.
Plattformübergreifende Unterstützung
Dies ist ein technischer Unterschied, der zu wichtigen realen Konsequenzen führt: Es ist einfacher, plattformübergreifende Programme mit einer interpretierten Programmiersprache zu erstellen.
Das liegt daran, dass Sie größtenteils nur ein Programm für die Interpreter-Plattform erstellen. Es ist der Interpreter selbst, der es in die richtige Form für die reale Plattform (z.B. Windows/Linux und x86/ARM) übersetzt. Natürlich gibt es noch einige Unterschiede zwischen den einzelnen Plattformen, die Sie beachten müssen. Ein gängiges Beispiel ist das Verzeichnistrennzeichen.
Wenn Sie ein Programm kompilieren, müssen Sie sich selbst um all die kleinen Unterschiede zwischen den einzelnen Plattformen kümmern. Das liegt zum Teil daran, dass kompilierte Sprachen in der Regel Low(er)level-Sprachen sind, wie z.B. C++, so dass man weniger Zugriff auf das System und damit mehr Verantwortung hat. Ein weiterer Grund ist, dass alle Bibliotheken, die Sie verwenden, selbst verschiedene Plattformen unterstützen müssen. Wenn sie also Windows nicht unterstützen, können Sie Windows auch nicht unterstützen.
Geschwindigkeit hat mehrere Gesichter
Auch im Fall der Geschwindigkeit haben wir eine Art Paradoxon: ein Compiler ist sowohl schneller als auch langsamer als ein Interpreter. Viele Leute wissen, dass ein kompiliertes Programm viel schneller ist als ein interpretiertes, aber das ist nicht das ganze Bild. Ein kompiliertes Programm ist schneller als ein interpretiertes Programm, aber es braucht mehr Zeit, ein Programm zu kompilieren und auszuführen, als es nur zu interpretieren.
Ein Compiler erzeugt tatsächlich schnellere Programme. Das liegt vor allem daran, dass er jede Anweisung nur einmal analysieren muss, während ein Interpreter sie jedes Mal analysieren muss. Außerdem kann ein Compiler den von ihm erzeugten ausführbaren Code optimieren. Das liegt zum einen daran, dass er genau weiß, wo er ausgeführt wird, und zum anderen daran, dass es Zeit kostet, den Code zu optimieren. Zeit, die die Interpretation zu langsam machen würde.
Laufzeitgeschwindigkeit versus Entwicklungsgeschwindigkeit
Man könnte meinen, dies sei pingelig: Wenn man ein Programm kompiliert, läuft es schneller, die Zeit, die es zum Kompilieren braucht, spielt keine Rolle. Das ist normalerweise die Meinung der alten Schule. Und zweifellos wird das resultierende Programm öfter ausgeführt, als es kompiliert wird. Wen kümmert es also, wenn die Entwicklung mehr Zeit in Anspruch nimmt? Sicherlich ist die Einstellung, dass die Entwicklung mehr Zeit in Anspruch nimmt, in gewisser Weise bewundernswert. Aber was ist, wenn die Laufzeitgewinne nicht relevant sind, während die Produktivitätsverluste bei der Entwicklung erheblich sind?
Es ist eine Sache, wenn Sie ein Betriebssystem erstellen, und eine andere, wenn Sie eine Selfie-App entwickeln. Sogar Ihre Nutzer ziehen vielleicht einen nicht einmal merklichen Verlust an Laufzeitgeschwindigkeit vor, um dafür schneller an Funktionen zu kommen. Es gibt keine allgemeingültige Antwort: In manchen Kontexten ist Produktivität wichtiger als Geschwindigkeit, in anderen ist es umgekehrt.
Die Geheimnisse des Debugging
Es gibt noch einen weiteren Aspekt, der unsicherer ist, als man denken würde: das Debugging. Auf dem Papier ist das Debugging bei der Verwendung eines Interpreters einfacher als bei der Verwendung eines Compilers. Das ist aus mehreren Gründen wahr:
- Mit dem Interpreter gibt es nur eine Version der ausführbaren Datei; Sie brauchen keine Debug-Version für die Entwicklung und eine Release-Version für den Endbenutzer
- Es gibt weniger plattformspezifische Fehler bei der Verwendung eines Interpreters
- , da der Interpreter den Code „on the fly“ umwandelt, Da der Interpreter eine Anweisung nach der anderen ausführt, ist es einfacher, einen Fehler zu finden
Der Unterschied, den Entwicklungswerkzeuge ausmachen
Während all dies in der Praxis zutrifft, ist es vielleicht weniger relevant, als es scheint. Wenn Sie über Ihre Erfahrungen nachdenken, werden Sie wahrscheinlich feststellen, dass das Debuggen von JavaScript schwieriger ist als das Debuggen von C++. Warum ist das so? Das liegt zum Teil am Design der Sprachen selbst. JavaScript verwendet eine dynamische Typisierung, während C++ eine statische Typisierung verwendet. Letzteres macht es einfacher, Fehler frühzeitig zu erkennen. Letztendlich kommt es aber auf die Entwicklungswerkzeuge an. C++ von Hand zu kompilieren ist schwierig, daher verwenden die meisten Leute IDEs, um damit zu entwickeln. Andererseits kann man für die Entwicklung von JavaScript problemlos Texteditoren und Kommandozeilen-Tools verwenden.
Das bedeutet, dass man, wenn man mit C++ entwickelt, auch C++ debuggen kann. Stattdessen kann man mit JavaScript entwickeln, ohne zu wissen, wie man JavaScript richtig debuggt.
Wenn man die beiden in den gleichen Kontext stellt, jeder mit einer großartigen IDE und unterstützenden Tools, wird die Situation wieder normal. In der Tat werden viele interpretierte Umgebungen von Leuten benutzt, die eine neue Sprache lernen wollen. Es ist einfacher zu testen und herauszufinden, was richtig und was falsch ist, wenn man sich ansieht, was Zeile für Zeile und in Echtzeit passiert.
Zusammenfassung
Wir haben die wichtigsten Unterschiede zwischen einem Compiler und einem Interpreter gesehen. Noch wichtiger ist, dass wir gesehen haben, dass die Folgen der unterschiedlichen Philosophien wichtiger sind als die technischen. Kurz gesagt, es gibt Kulturen, die mit bestimmten technischen Entscheidungen einhergehen, die letztendlich für sich selbst relevant sind. Wenn Sie eine schnelle und einfache Entwicklung wollen, werden Sie alle Technologien für Geschwindigkeit wählen und nicht nur eine. Und Ihre Benutzer werden Ihrem Beispiel folgen.
Dies ist ein entscheidender Aspekt, über den man nachdenken muss, besonders wenn man eine eigene Programmiersprache entwickeln will. Rasmus Lerdorf hat PHP entwickelt, damit es einfach zu benutzen ist. Und in der Tat war es im Vergleich zu den Alternativen unglaublich einfach zu benutzen, zumindest zur Zeit seiner Entwicklung. Aber es begann mehr als eine Bibliothek denn als eine Sprache. Und obwohl es sich stark verbessert hat, leidet es immer noch unter seinen Anfängen. Man kann immer noch guten PHP-Code erstellen, aber weniger Nutzer als sonst tun dies. Denn wenn man nur etwas braucht, das funktioniert, Sicherheit, Wartung usw., kommt der ganze Rest später.
Wenn Sie wissen wollen, wie Sie praktisch einen Interpreter oder einen Compiler für Ihre Sprache bauen können, sollten Sie sich die Ressourcen zur Erstellung einer Programmiersprache ansehen. Wenn du das lernen willst, und alles, was du brauchst, um deine eigene Sprache zu erstellen, brauchst du nur ein großartiges Buch zu nehmen, das von Kindern und Erwachsenen gleichermaßen geliebt wird, wie man pragmatische, leichte Sprachen erstellt.
5 Dinge, die man beim Erstellen einer Sprache beachten sollte
Erhalten Sie die Checkliste per E-Mail und weitere Tipps zum Erstellen von Sprachen
Schreibe einen Kommentar