Menu

Ein C-Programm kompilieren und ausführen (gcc, Schritt für Schritt)

Aus einer .c-Datei ein laufendes Programm machen: der gcc-Befehl, was Präprozessor, Compiler und Linker tatsächlich tun, die Flags, die sich vom ersten Tag an lohnen, und wie man die Fehler liest, wenn es schiefgeht.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

C ist eine kompilierte Sprache: Nichts läuft, bevor ein Compiler deinen Quelltext in Maschinencode für deine konkrete CPU und dein Betriebssystem übersetzt hat. Dieser Schritt ist ein Befehl, aber zu wissen, was er tut, macht die meisten Fehlermeldungen von rätselhaft zu offensichtlich.

Die zwei Befehle

Speichere das hier als hello.c:

#include <stdio.h>

int main(void) {
    printf("Hallo, C!\n");
    return 0;
}

Dann, im selben Ordner:

gcc hello.c -o hello
./hello

Der erste Befehl kompiliert. Der zweite führt das Ergebnis aus. Unter Windows lautet der Startbefehl hello in der Eingabeaufforderung oder .\hello in PowerShell - es gibt kein ./-Präfix, weil Windows standardmäßig im aktuellen Verzeichnis sucht und Unix-Shells das bewusst nicht tun.

Lässt du -o hello weg, nennt gcc die Ausgabe a.out (oder a.exe), weshalb ältere Anleitungen mit ./a.out enden. Benenne deine Ausgabe immer; es kostet vier Zeichen und erspart Verwirrung.

Hier ist dasselbe Programm im Browser-Editor, der beide Schritte für dich erledigt:

Was „Kompilieren" tatsächlich tut

gcc hello.c -o hello sieht nach einem Schritt aus. Es sind vier, und jeder kann mit seiner eigenen Fehlerart scheitern.

1. Präprozessor. Bevor irgendein C übersetzt wird, behandelt der Präprozessor jede Zeile, die mit # beginnt. #include <stdio.h> wird buchstäblich durch den Inhalt dieser Header-Datei ersetzt; #define-Makros werden expandiert; #ifdef-Blöcke bleiben erhalten oder werden gelöscht. Das Ergebnis ist eine große C-Datei ohne übrige #-Zeilen. Du kannst sie ansehen:

gcc -E hello.c

Das gibt Hunderte Zeilen aus - fast alles davon ist das eingefügte stdio.h.

2. Übersetzen. Das vorverarbeitete C wird geparst, typgeprüft und in Assembler für deine CPU übersetzt. Von hier kommen Syntaxfehler, Typfehler und Warnungen.

3. Assemblieren. Aus dem Assembler wird eine Objektdatei - Maschinencode mit Platzhaltern dort, wo Aufrufe von Funktionen aus anderen Dateien stehen.

gcc -c hello.c   # erzeugt hello.o, stoppt vor dem Linken

4. Linken. Die Objektdateien werden mit der C-Standardbibliothek zusammengenäht, jeder Platzhalter mit einer echten Adresse gefüllt, und das Ergebnis ist eine ausführbare Datei. Von hier kommen die „undefined reference"-Fehler.

Die praktische Erkenntnis: Ein Übersetzungsfehler zeigt auf eine Zeile in deinem Quelltext, ein Linkfehler nicht, weil das Linken erst passiert, nachdem jede Zeile bereits akzeptiert wurde.

Flags, die sich ab Tag eins lohnen

Das nackte gcc datei.c -o prog akzeptiert eine Menge gefährlichen Code stillschweigend. Vier Flags ändern das.

gcc -std=c17 -Wall -Wextra -g hello.c -o hello
  • -Wall schaltet die üblichen Warnungen ein. Trotz des Namens sind es nicht „alle" Warnungen - es ist die vernünftige Auswahl.
  • -Wextra fügt weitere hinzu, darunter unbenutzte Parameter und einige Vergleichsfehler.
  • -std=c17 legt den Sprachstandard fest, damit dein Code auf jeder Maschine dasselbe bedeutet. Nimm -std=c99, wenn du älterem Material folgst.
  • -g behält Debug-Informationen, damit gdb oder lldb bei einem Absturz deine tatsächlichen Quelltextzeilen zeigen können.

Zwei weitere, die du irgendwann willst:

  • -O2 schaltet die Optimierung für Release-Builds ein. Lass es beim Lernen weg: Optimierter Code ist schwerer zu debuggen, und Warnungen verschieben sich manchmal.
  • -fsanitize=address,undefined (gcc und clang) bricht das Programm mit einer klaren Meldung in dem Moment ab, in dem es außerhalb der Grenzen liest oder auf undefiniertes Verhalten trifft. Das ist das nützlichste Lern-Flag in C.

Probiere die Warnungen selbst aus. Dieses Programm kompiliert und läuft, hat aber zwei echte Bugs:

count bekommt nie einen Wert, das Programm gibt also die Bytes aus, die zufällig dort lagen. Mit -Wall sagt der Compiler das: 'count' is used uninitialized. Warnungen sind in C fast nie Rauschen - behandle sie als Fehler, die du nur noch nicht getroffen hast.

Mehr als eine Datei kompilieren

Echte Programme sind auf Dateien verteilt. Übergib sie alle an gcc:

gcc -std=c17 -Wall main.c utils.c -o myprog

Oder kompiliere jede einzeln und linke am Ende, was Build-Systeme tun, damit das Ändern einer Datei nicht alles neu baut:

gcc -c main.c      # -> main.o
gcc -c utils.c     # -> utils.o
gcc main.o utils.o -o myprog

Manche Bibliotheken brauchen ein ausdrückliches Link-Flag. Die Mathematikbibliothek ist die, der jeder Anfänger begegnet:

gcc calc.c -o calc -lm

Ohne -lm kompiliert die Nutzung von sqrt aus math.h problemlos und scheitert dann beim Linken mit undefined reference to sqrt - die Deklaration stand im Header, aber der Code lag in einer Bibliothek, nach der niemand gefragt hat.

Die Fehler lesen

C-Fehler sind knapp, aber konsistent. Drei Beispiele decken das meiste ab, was dir früh begegnet.

Ein fehlendes Semikolon wird in der nächsten Zeile gemeldet, weil der Compiler weitergelesen hat:

hello.c:5:5: error: expected ';' before 'return'

Die Lösung gehört in Zeile 4, nicht Zeile 5. Wann immer ein Fehler auf eine Zeile zeigt, die in Ordnung aussieht, prüfe die Zeile davor.

Ein fehlender Header sieht aus wie ein Rätsel über eine Funktion, die du offensichtlich richtig geschrieben hast:

hello.c:4:5: warning: implicit declaration of function 'printf'

Das bedeutet, dass der Compiler nie eine Deklaration für printf gesehen hat, du hast also #include <stdio.h> vergessen. In C99 und später ist das ein Fehler, nicht nur eine Warnung.

Ein Linkfehler hat überhaupt keine Zeilennummer:

/usr/bin/ld: main.o: in function `main':
main.c:(.text+0x1a): undefined reference to `helper'

Der Compiler hat dir geglaubt, dass helper irgendwo existiert; der Linker hat nachgesehen und es gibt ihn nicht. Entweder hast du die Definition nie geschrieben, sie anders geschrieben oder vergessen, die Datei mit ihr an gcc zu übergeben.

Behebe immer den ersten Fehler. C-Fehler ziehen Kaskaden nach sich - eine schlechte Zeile kann zwanzig Meldungen erzeugen, und neunzehn davon verschwinden, wenn die erste behoben ist.

Exit-Codes

return 0 aus main ist keine Zierde. Es ist der Exit-Status des Programms, und die Shell kann ihn lesen:

Nach dem Lauf gibt echo $? unter macOS/Linux (oder echo %errorlevel% unter Windows) diese Zahl aus. Skripte und Build-Werkzeuge entscheiden damit, ob sie weitermachen. Die Konvention ist absolut: 0 ist Erfolg, und ungleich null ist ein Fehlercode deiner Wahl. stdlib.h definiert EXIT_SUCCESS und EXIT_FAILURE, wenn du die Namen bevorzugst.

Seit C99 wird das Herausfallen aus main ohne return wie return 0 behandelt - aber es hinzuschreiben ist klarer, und für jede andere Funktion ist es Pflicht.

Häufig gestellte Fragen

Wie kompiliere und starte ich ein C-Programm?

Speichere den Code als hello.c, führe dann gcc hello.c -o hello zum Bauen und ./hello zum Starten aus (unter Windows nur hello). Wenn gcc nicht gefunden wird, musst du zuerst einen Compiler installieren.

Was bewirkt gcc -o?

-o benennt die Ausgabedatei. gcc hello.c -o hello erzeugt eine ausführbare Datei namens hello. Ohne -o schreibt gcc nach a.out (oder a.exe unter Windows), weshalb so viele alte Anleitungen ./a.out ausführen.

Welche gcc-Flags sollte ich immer benutzen?

gcc -std=c17 -Wall -Wextra -g deinedatei.c -o deinprogramm. -Wall -Wextra schalten die Warnungen ein, die echte Bugs finden, -std=c17 legt die Sprachversion fest, und -g behält Debug-Symbole, damit ein Debugger deinen Quelltext zeigen kann. Füge -O2 hinzu, wenn du in einem Release-Build Tempo willst.

Was bedeutet „undefined reference to" in C?

Das ist ein Linkerfehler: Der Compiler hat einen Aufruf der Funktion akzeptiert, aber es wurde keine Definition dieser Funktion gefunden. Häufige Ursachen sind ein Tippfehler im Namen, eine vergessene zweite .c-Datei oder die Nutzung einer Mathematikfunktion ohne Linken der Mathematikbibliothek (-lm).

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S