
Das ist es — die letzte Unit des gesamten Kurses! 🎉 Und wir schließen mit einem der wichtigsten Konzepte echter Projekte ab: Wie du ein Programm in mehrere Dateien aufteilst. Das unterscheidet Hobby-Code von professioneller Entwicklung. Du schaffst das!
1. Warum mehrere Dateien?
Stell dir vor, ein Programm hat 10.000 Zeilen Code — alles in einer einzigen .c-Datei. Niemand kann das lesen, niemand kann darin etwas finden, und Teamarbeit ist unmöglich. Die Lösung: Modularisierung.
❌ Problem: Eine riesige Datei
- Unlesbar und schwer wartbar
- Teamarbeit ist nicht möglich
- Kein Code kann wiederverwendet werden
- Jede kleine Änderung erfordert vollständige Neukompilierung
✅ Lösung: Mehrere Module
- Bessere Übersicht — jede Datei hat eine klare Aufgabe
- Teamarbeit: jeder arbeitet an seinen Dateien
- Wiederverwendung: Module in anderen Projekten nutzen
- Schnellere Kompilierung: nur geänderte Dateien neu kompilieren
Analogie
Ein Buch hat Kapitel — ein Programm hat Module. Kein Leser möchte ein 500-seitiges Buch ohne Gliederung lesen, genauso wenig möchte ein Entwickler eine Mammutdatei durchsuchen.
2. Header-Dateien (.h) vs. Quelldateien (.c)
Das Kernprinzip: Was gibt es? kommt in die .h-Datei, Wie funktioniert es? kommt in die .c-Datei.
| Datei | Enthält | Beispiel |
|---|---|---|
| .h Header | Deklarationen, Typen, Makros — die Schnittstelle (Interface) | int addiere(int a, int b); |
| .c Quelle | Definitionen (Implementierung) — der echte Code | int addiere(int a, int b) { return a+b; } |
Header = "Was gibt es?"
Die .h-Datei ist wie ein Inhaltsverzeichnis oder eine Speisekarte: Sie listet auf, welche Funktionen, Typen und Konstanten ein Modul bereitstellt — ohne zu verraten, wie sie funktionieren.
Source = "Wie funktioniert es?"
Die .c-Datei enthält die eigentliche Implementierung: den kompletten Funktionsrumpf mit dem echten Code. Wer das Modul nutzt, muss diesen Teil nicht kennen.
Goldene Regel
Declare in .h — Define in .c
Deklarationen (Prototypen) gehören in den Header. Definitionen (Implementierungen) gehören in die Quelldatei.
3. Include Guards — unverzichtbar in jedem Header
Was passiert, wenn zwei verschiedene Dateien denselben Header einbinden? Ohne Schutz: doppelte Deklaration — Compilerfehler! Die Lösung sind Include Guards:
#ifndef RECHNER_H #define RECHNER_H // Deklarationen — nur einmal eingebunden, egal wie oft #include int addiere(int a, int b); int subtrahiere(int a, int b); #endif /* RECHNER_H */
Wie Include Guards funktionieren
#ifndef RECHNER_H— "WennRECHNER_Hnoch NICHT definiert ist …"#define RECHNER_H— "… dann definiere es jetzt …"- Alle Deklarationen dazwischen werden einmal verarbeitet
#endif— Ende des bedingten Blocks- Beim zweiten
#includeder selben Datei:RECHNER_Hist schon definiert → der gesamte Block wird übersprungen
Konvention für Guard-Namen
Dateiname in Großbuchstaben, Punkte durch Unterstriche ersetzen:
rechner.h→RECHNER_Hstring_utils.h→STRING_UTILS_Hmein_modul.h→MEIN_MODUL_H
4. Vollständiges 3-Datei-Beispiel
Das Standardbeispiel: ein rechner-Modul mit Header, Implementierung und Hauptprogramm:
#ifndef RECHNER_H #define RECHNER_H int addiere( int a, int b); int subtrahiere( int a, int b); float dividiere( float a, float b); #endif
#include "rechner.h" int addiere( int a, int b) { return a + b; } int subtrahiere( int a, int b) { return a - b; } float dividiere( float a, float b) { return b != 0 ? a/b : 0; }
#include <stdio.h> #include "rechner.h" int main() { printf( "5+3=%d\n", addiere( 5, 3)); printf( "10/4=%.2f\n", dividiere( 10, 4)); return 0; }
5. Kompilierung mehrerer Dateien
Beim Kompilieren müssen alle .c-Dateien angegeben werden (nicht die .h-Dateien — die werden automatisch per #include eingebunden):
# Alle .c-Dateien auf einmal kompilieren gcc main.c rechner.c -o rechner # Oder: Separat kompilieren (nur geänderte Dateien nötig) gcc -c rechner.c -o rechner.o # erzeugt Objektdatei gcc -c main.c -o main.o # erzeugt Objektdatei gcc main.o rechner.o -o rechner # linkt zusammen
Was macht gcc -c?
Der Flag -c bedeutet "nur kompilieren, nicht linken". Das Ergebnis ist eine Objektdatei (.o) — maschinennaher Code, aber noch kein ausführbares Programm. Erst der Linker verbindet alle .o-Dateien zu einem Programm.
Vorteil separater Kompilierung
Bei 10 Dateien und einer Änderung in nur einer: nur diese eine Datei neu kompilieren, dann neu linken. Bei großen Projekten spart das enorm viel Zeit. Makefiles automatisieren genau das.
Makefiles — der nächste Schritt
Ein Makefile definiert Regeln für die Kompilierung: welche Dateien voneinander abhängen, in welcher Reihenfolge kompiliert wird. Statt langen GCC-Befehlen reicht dann ein einfaches make. Das Arbeitsblatt zu dieser Unit enthält ein vollständiges Makefile-Beispiel!
6. Typische Projektstruktur
So sieht ein gut organisiertes C-Projekt mit mehreren Modulen aus:
Jedes Modul besteht aus genau einem Paar: modul.h und modul.c. Das macht die Struktur vorhersagbar und leicht navigierbar.
7. Was kommt in den Header? Was in die .c?
| Gehört in .h (Header) | Gehört in .c (Quelldatei) |
|---|---|
| Funktionsdeklarationen (Prototypen) | Funktionsdefinitionen (mit Implementierung) |
typedef, struct, enum Definitionen | Lokale Variablen und Hilfsfunktionen |
#define Konstanten und Makros | static Funktionen (nur intern) |
extern Variablendeklarationen | Globale Variablendefinitionen |
Include Guards (#ifndef…#endif) | #include "eigener_header.h" |
⚠️ NIEMALS Variablen in .h definieren!
Wenn du int zaehler = 0; in eine .h-Datei schreibst und diese Header von drei .c-Dateien eingebunden wird, entstehen drei Definitionen derselben Variable — das führt zu einem Linker-Fehler (multiply defined symbol).
Richtig: In der .h-Datei nur extern int zaehler; (Deklaration), in genau einer .c-Datei int zaehler = 0; (Definition).
8. Häufige Fehler
| Fehler | Folge | Lösung |
|---|---|---|
Variable in .h definieren | Linker-Fehler: multiply defined | extern in .h, Definition in .c |
| Include Guard vergessen | Doppelte Deklaration, Compilerfehler | #ifndef/#define/#endif hinzufügen |
| Zirkuläre Includes (a.h → b.h → a.h) | Endlosschleife im Präprozessor | Forward Declarations verwenden |
Falscher Pfad bei #include "..." | Compilerfehler: file not found | Pfad relativ zur aktuellen Datei angeben |
.h-Datei im GCC-Befehl angeben | Compilerfehler oder unerwartetes Verhalten | Nur .c-Dateien kompilieren; .h wird per #include eingebunden |
#include <...> statt "..." für eigene Dateien | Datei wird nicht gefunden | "..." für eigene, <...> für Systemheader |
✅ Checkliste für jeden neuen Header
- Include Guard hinzufügen (
#ifndef DATEI_H/#define DATEI_H/#endif) - Nur Deklarationen, keine Definitionen
- Keine Variablendefinitionen (nur
extern) - In der zugehörigen
.c-Datei den eigenen Header einbinden:#include "datei.h" - Alle
.c-Dateien im GCC-Befehl angeben
⚡ Code-Simulator
main.c mit den Funktionen direkt eingebunden, damit du die Logik testen kannst. Auf deinem PC würdest du alle drei Dateien anlegen und mit gcc main.c rechner.c -o rechner kompilieren.
Die drei Dateien des rechner-Projekts:
#ifndef RECHNER_H #define RECHNER_H int addiere(int a, int b); int subtrahiere(int a, int b); float dividiere(float a, float b); #endif /* RECHNER_H */
#include "rechner.h" int addiere(int a, int b) { return a + b; } int subtrahiere(int a, int b) { return a - b; } float dividiere(float a, float b) { return b != 0 ? a/b : 0; }
#include <stdio.h> #include "rechner.h" // Eigene Header mit "" int main() { printf("5 + 3 = %d\n", addiere(5, 3)); printf("10 - 4 = %d\n", subtrahiere(10, 4)); printf("10 / 4 = %.2f\n", dividiere(10, 4)); return 0; }
Im Simulator unten kannst du die Logik der Funktionen direkt testen — alle drei Dateien sind zusammengeführt, damit printf simuliert werden kann:

Im echten Projekt liegen diese Teile in separaten Dateien. Der Simulator zeigt dir, dass die Funktionslogik korrekt ist. Probiere eigene Funktionen aus — ändere die Zahlen oder füge neue Berechnungen hinzu!
🎯 Wissens-Quiz
📋 Spickzettel
Vollständiges Mini-Projekt (3 Dateien)
#ifndef RECHNER_H #define RECHNER_H int addiere(int a, int b); float dividiere(float a, float b); #endif
#include "rechner.h" int addiere(int a, int b) { return a + b; } float dividiere(float a, float b) { return b != 0 ? a/b : 0; }
gcc main.c rechner.c -o rechner
✅ Checkliste Unit 36 — und des gesamten Kurses!
- Ich verstehe den Unterschied zwischen .h und .c Dateien
- Ich kann Include Guards korrekt schreiben
- Ich weiß, was in den Header gehört und was in die Quelldatei
- Ich kann mit GCC mehrere .c-Dateien zu einem Programm kompilieren
- Ich kenne die häufigsten Fehler (Variable in .h, kein Include Guard)
- Ich habe alle 36 Units von "Ömer erklärt C" abgeschlossen! 🎉

Du hast es geschafft! 36 Units, von den Grundlagen bis zu professioneller Modularisierung. Jetzt kennst du die Bausteine echter C-Projekte. Ob du weiter in C tiefer gehst, zu C++ wechselst oder ein eigenes Projekt startest — du hast das Fundament. Glückwunsch und viel Erfolg! 🏆