Menu
Coddy logo textTech

Was ist ein Compiler?

Ein Compiler ist ein Programm, das Quellcode aus einer Programmiersprache in Maschinencode oder eine andere niedrigere Form wie Bytecode übersetzt, bevor das Programm läuft. Das übersetzte Programm kann danach ohne den ursprünglichen Quellcode laufen.

Von Kevin Spektor, Mitgründer & CTO

Aktualisiert am 24. September 2026

Quellcode
  1. 1print("Hello")
  2. 2total = 2 + 3
  3. 3print(total)
  4. 4print("Done")
Ausgabe
Kompiliervorgänge0
Ausführungen0

Einmal kompilieren, dann das Programm beliebig oft ausführen: Der Zähler für Ausführungen steigt, der für Kompiliervorgänge nicht. Schalte den Tippfehler ein, und der Compiler lehnt das ganze Programm ab, also wird nichts ausgegeben.

Speichere dieses C-Programm als hello.c:

#include <stdio.h>

int main(void) {
    int price = 4;
    printf("Total: %d\n", price * 3);
    return 0;
}

Tippe dann gcc hello.c -o hello. Einen Moment lang passiert nichts Sichtbares, dann erscheint neben deinem Quellcode eine neue Datei namens hello. Diese Datei ist die Ausgabe des Compilers: Maschinencode, den dein Prozessor ausführen kann. Lösch hello.c, und ./hello funktioniert trotzdem, denn alles, was das Programm braucht, ist bereits übersetzt.

gcc hello.c -o hello
./hello
Total: 12

Wie ein Compiler arbeitet, Schritt für Schritt

Ein Compiler liest Quellcode als reinen Text und arbeitet ihn in Stufen durch. Nimm die einzelne Zeile total = price * 3:

  1. Lexikalische Analyse. Der Text wird in Tokens zerlegt, die „Wörter“ der Sprache: der Name total, der Operator =, der Name price, der Operator *, die Zahl 3. Leerzeichen und Kommentare fallen hier weg.
  2. Parsing. Die Tokens werden zu einem Syntaxbaum angeordnet, der die Struktur festhält: eine Zuweisung, deren Wert eine Multiplikation von price und 3 ist. Code, der gegen die Grammatik der Sprache verstößt, bleibt hier mit einem Syntaxfehler stecken.
  3. Semantische Analyse. Der Compiler prüft die Bedeutung: Ist price deklariert, passen die Typen zusammen, gibt es die aufgerufene Funktion?
  4. Optimierung. Das Programm wird so umgeschrieben, dass es schneller läuft oder weniger Speicher braucht, ohne zu ändern, was es tut. Aus x * 2 kann ein einzelner Shift-Befehl werden, und Code, der nie laufen kann, wird entfernt.
  5. Codeerzeugung. Der Compiler schreibt die Ausgabe für ein Ziel: Maschinencode für x86-64 oder ARM oder Bytecode für eine virtuelle Maschine.

Bei C und C++ fügt ein letzter Schritt, das Linken, deine kompilierten Dateien mit Bibliothekscode (etwa printf aus der C-Standardbibliothek) zu einer ausführbaren Datei zusammen. gcc startet den Linker für dich, deshalb fühlt es sich wie ein einziger Befehl an.

Python liefert die ersten beiden Stufen als Standardmodule mit, also kannst du ihnen an echter Eingabe bei der Arbeit zusehen:

NAME 'total'
OP '='
NAME 'price'
OP '*'
NUMBER '3'
Assign(
  targets=[
    Name(id='total', ctx=Store())],
  value=BinOp(
    left=Name(id='price', ctx=Load()),
    op=Mult(),
    right=Constant(value=3)))

Mit diesem Baum arbeitet der Rest des Compilers. Leerzeichen und Zeilenumbrüche spielen keine Rolle mehr, nur noch die Struktur: Weise total das Ergebnis der Multiplikation von price mit 3 zu.

Kompilierzeit: Fehler, die vor dem Programmstart gefunden werden

Weil ein Compiler das ganze Programm liest, bevor irgendetwas davon läuft, kann er Fehler früh ablehnen. In diesem Beispiel läuft keine der drei print-Zeilen in source, nicht einmal die erste, denn Pythons Compiler weist den Text zurück, bevor die Ausführung beginnt:

Rejected before running anything:
  '(' was never closed (line 3)

Compiler für statisch typisierte Sprachen finden mehr als Syntaxfehler. Diese C-Zeile in einer Datei namens bad.c ist grammatisch korrekt, speichert aber Text in einer Ganzzahlvariablen:

int count = "five";

GCC 14 und neuer brechen mit einem Fehler ab:

bad.c:4:17: error: initialization of 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]

Derselbe Fehler würde in Python erst auffallen, wenn diese Zeile läuft. Ihn schon zur Kompilierzeit zu finden, ist ein Grund, warum große Teams kompilierte, statisch typisierte Sprachen wählen. Alles findet ein Compiler aber nicht: Eine Division durch eine Zahl, die sich als null herausstellt, oder das Lesen einer Datei, die nicht existiert, scheitert trotzdem erst zur Laufzeit.

Beispiele für Compiler

CompilerLiestErzeugt
GCC, ClangC, C++Maschinencode für x86-64, ARM und andere
MSVC (Microsoft Visual C++)C, C++Ausführbare Windows-Dateien (.exe, .dll)
javacJavaJVM-Bytecode (.class-Dateien)
rustcRustMaschinencode
go buildGoEine einzelne ausführbare Datei
tscTypeScriptJavaScript

Zwei Zeilen zeigen, dass Maschinencode nicht die einzig mögliche Ausgabe ist. javac erzeugt Bytecode, den die Java Virtual Machine ausführt, ein Teil der Java-Laufzeitumgebung. tsc macht aus TypeScript JavaScript, also wieder eine Hochsprache; ein Compiler, der so etwas tut, heißt oft Transpiler.

Kompilierter Maschinencode ist an eine CPU-Familie und ein Betriebssystem gebunden. Ein Programm, das für Windows auf x86-64 kompiliert wurde, läuft nicht auf einem Mac mit einem Apple-Chip der M-Serie; du kompilierst denselben Quellcode für jedes Ziel neu.

Compiler oder Interpreter

Ein Interpreter führt Quellcode direkt aus, statt eine separate Programmdatei zu erzeugen. So werden Python und Ruby üblicherweise ausgeführt. Die meisten modernen Sprachwerkzeuge nutzen beide Ideen: CPython kompiliert deine Datei zu Bytecode und interpretiert ihn dann, und die JVM und die JavaScript-Engine V8 kompilieren häufig genutzten Code zur Laufzeit in Maschinencode. Die vollständige Gegenüberstellung findest du auf der Seite Compiler vs. Interpreter.

Häufige Irrtümer

  • „Wenn es kompiliert, funktioniert es.“ Ein Compiler prüft, ob das Programm gültig ist, nicht ob es richtig ist. Logikfehler und Laufzeitfehler wie eine Division durch null kommen durch.
  • „Python wird nicht kompiliert.“ CPython kompiliert jede Datei zu Bytecode, bevor es sie ausführt. Die .pyc-Dateien in __pycache__-Ordnern sind dieser Bytecode, gespeichert für die Module, die dein Programm importiert, damit der nächste Lauf den Schritt überspringen kann.
  • „Ein Online-Compiler ist ein Compiler.“ Websites, die deinen Code im Browser ausführen, schicken ihn an einen Server, der die ganze Toolchain laufen lässt (Compiler, Linker und das Programm selbst) und die Ausgabe zurückgibt. Der Compiler ist nur ein Teil davon.
  • „Kompilierter Code läuft überall.“ Er läuft auf der CPU und dem Betriebssystem, für die er gebaut wurde. Portabilität entsteht durch erneutes Kompilieren oder durch eine virtuelle Maschine wie die JVM.

Wie es weitergeht

Die C-Doku zeigt einen Compiler im Alltag: C kompilieren und ausführen geht Präprozessor, Kompilieren, Assemblieren und Linken mit echten gcc-Befehlen durch. Um den anderen Weg der Codeausführung kennenzulernen, lies Compiler vs. Interpreter und danach Laufzeitumgebung für alles, was ein Programm umgibt, sobald es startet. Der C-Kurs ist ein guter Ort, um mit einer kompilierten Sprache zu üben.

Häufig gestellte Fragen

Aus welchen Teilen besteht ein Compiler?
Ein Compiler wird meist in drei Teilen beschrieben. Das Frontend liest den Quellcode, zerlegt ihn in Tokens, parst ihn zu einem Syntaxbaum und prüft die Typen. Das Middle End optimiert eine Zwischenform des Programms, und das Backend erzeugt Maschinencode oder Bytecode für die Ziel-CPU.
Wie kann sich ein Compiler selbst kompilieren?
Durch Bootstrapping. Die erste Version eines Compilers wird in einer bestehenden Sprache geschrieben oder von einem älteren Compiler übersetzt und dann benutzt, um die nächste Version zu kompilieren, die in der neuen Sprache selbst geschrieben ist. GCC zum Beispiel ist größtenteils in C und C++ geschrieben und wird mit einem vorhandenen C++-Compiler gebaut, oft mit einem älteren GCC.
Was ist der Unterschied zwischen einem Compiler und einem Assembler?
Ein Compiler übersetzt eine Hochsprache wie C oder Rust, in der eine Zeile zu vielen Maschinenbefehlen werden kann. Ein Assembler übersetzt Assemblersprache, in der jede Zeile fast eins zu eins einem einzelnen Maschinenbefehl entspricht. Compiler wie GCC erzeugen oft zuerst Assemblercode und geben ihn an einen Assembler weiter.
Was ist ein JIT-Compiler?
Ein Just-in-time-Compiler (JIT) übersetzt Code in Maschinencode, während das Programm läuft, statt vorher. Er beobachtet, welche Teile am häufigsten laufen, und kompiliert genau diese, sodass ein lange laufendes Programm mit der Zeit schneller wird. Die JVM, die JavaScript-Engine V8 und PyPy nutzen alle JIT-Kompilierung.
Muss ich einen Compiler installieren, um programmieren zu lernen?
Am Anfang nicht. Editoren im Browser und Online-Playgrounds führen den Compiler oder Interpreter für dich auf einem Server aus. Wenn du auf deinem eigenen Rechner arbeitest, brauchen C und C++ einen Compiler wie GCC oder Clang, Java ein JDK und Python den Python-Interpreter.
Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S