MINT lernen

Funktionen und Header

Wie verteilst du ein Programm so auf mehrere Dateien, dass Compiler und Linker am Ende doch alles zusammenfinden?

1

Eigene Funktionen

Wie in Python fasst du Anweisungen zu Funktionen zusammen — in C steht aber vor jeder Funktion ihr Rückgabetyp.

C · linien.c
#include <stdio.h>

int summe(int a, int b) {        // Rückgabetyp int, zwei Parameter
    return a + b;
}

void linie(int n) {              // void: kein Rückgabewert
    for (int i = 0; i < n; i++) {
        printf("-");
    }
    printf("\n");
}

int main(void) {
    int s = summe(3, 4);         // Aufruf, Ergebnis speichern
    printf("Summe: %d\n", s);
    linie(10);
    return 0;
}
Konsole
$ gcc linien.c -o linien
$ ./linien
Summe: 7
----------
  • Definition:Rückgabetyp name(Parameter) { … } — jeder Parameter bekommt einen Typ.
  • return:beendet die Funktion und liefert einen Wert vom Rückgabetyp zurück.
  • void:Funktion ohne Rückgabewert; return; ohne Wert ist erlaubt.
  • Aufruf:summe(3, 4) — Argumente in Klammern, Ergebnis weiterverwenden oder speichern.
  • Kopien:Parameter erhalten Kopien der Argumente (call by value): Änderungen bleiben in der Funktion.
C · kopie.c (Ausschnitt)
void verdopple(int x) {
    x = x * 2;                   // ändert nur die Kopie
    printf("in verdopple: %d\n", x);
}

int main(void) {
    int zahl = 5;
    verdopple(zahl);
    printf("in main: %d\n", zahl);
    return 0;
}
Konsole
in verdopple: 10
in main: 5
  • Reihenfolge:C liest von oben nach unten: Eine Funktion muss vor ihrem ersten Aufruf bekannt sein.
  • Prototyp:Kündigt eine Funktion an: int summe(int a, int b); — Kopf mit Semikolon, ohne Rumpf.
  • Ohne Prototyp:Steht die Definition erst nach main, meldet gcc: implicit declaration of function 'summe'.
2

Programme auf Dateien verteilen

Größere Programme teilt man auf mehrere Dateien auf — z. B. ein Modul rechner mit Rechenfunktionen und ein Hauptprogramm:

  • Header rechner.h:enthält nur die Prototypen — die „Speisekarte“ des Moduls.
  • rechner.c:enthält die Definitionen, also die Funktionsrümpfe.
  • main.c:enthält main und ruft die Funktionen auf.
  • #include "…":Anführungszeichen: eigene Datei im Projektordner; <…>: Systembibliothek.
  • Include-Guard:#ifndef RECHNER_H / #define RECHNER_H … #endif verhindert, dass der Header doppelt eingefügt wird.
  • Übersetzen:alle .c-Dateien angeben, nie die .h-Datei: gcc main.c rechner.c -o rechner.

Zerlege das Programm programm.c in Bausteine und lege sie auf die drei Dateien um: Ziehe einen Baustein in eine Datei — oder wähle ihn mit Enter, suche das Ziel mit den Pfeiltasten und lege ihn mit Enter ab. Prüfen vergleicht mit der üblichen Aufteilung, Übersetzen zeigt, was gcc dazu sagt.

Ein Programm, drei Dateien

Konsole (Fehlermeldungen von gcc 14)
$ 

Halte fest: In die Header-Datei gehören nur die Ankündigungen (Prototypen), eingerahmt vom Include-Guard; die Definitionen stehen in genau einer .c-Datei. Jede .c-Datei, die die Funktionen benutzt oder definiert, bindet den Header mit #include "rechner.h" ein.

Konsole
$ gcc main.c rechner.c -o rechner
$ ./rechner
49
9
5.5
Merke

Aufteilen: Prototypen in die .h-Datei (mit Include-Guard), Definitionen in die .c-Datei, einbinden mit #include "name.h", übersetzen mit gcc main.c name.c -o prog.

3

Allgemeine Hinweise

Semikolon nur beim Prototyp

int summe(int a, int b); kündigt an. Steht bei der Definition ein ; vor {, meldet gcc einen Syntaxfehler.

Keine Definitionen im Header

Bindet man einen Header mit Funktionsrümpfen in zwei .c-Dateien ein, meldet der Linker multiple definition.

Rückgabewert nutzen

Eine Funktion mit int liefert einen Wert — speichere ihn oder gib ihn aus, sonst geht das Ergebnis verloren.

Videos