Funktionsprototypen
Der Compiler liest dein Programm von oben nach unten, so wie du ein Buch liest. Wenn er an einen Funktionsaufruf kommt, muss er die Funktion schon kennen: ihren Namen, was sie entgegennimmt und was sie zurückgibt. Deshalb haben wir Funktionen bisher über main definiert. Dieses Programm hat die Funktion unter main:
#include <stdio.h>
int main(void) {
begruesse();
return 0;
}
void begruesse(void) {
printf("Hallo!\n");
}Es lässt sich nicht kompilieren:
main.c:4:5: error: call to undeclared function 'begruesse'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
4 | begruesse();
| ^
main.c:8:6: error: conflicting types for 'begruesse'
8 | void begruesse(void) {
| ^
main.c:4:5: note: previous implicit declaration is here
4 | begruesse();
| ^
2 errors generated.Beginne mit dem ersten Fehler. In Zeile 4 ruft main die Funktion begruesse auf, die noch nicht deklariert wurde: Nichts über Zeile 4 hat dem Compiler gesagt, dass es eine solche Funktion gibt. Der Rest der Zeile sagt, dass die Sprache seit C99, der Version von C aus dem Jahr 1999, keine impliziten Funktionsdeklarationen mehr erlaubt. Sehr alte Compiler haben früher geraten, wie eine unbekannte Funktion aussieht, und oft falsch geraten. Der zweite Fehler, conflicting types, folgt nur aus dem ersten: Der Compiler hat sich in Zeile 4 eine eigene Vermutung ausgedacht (die note sagt es), und die echte Funktion in Zeile 8 passt nicht dazu. Wenn du den ersten Fehler behebst, verschwindet auch der zweite.
Es gibt zwei Wege, das zu beheben. Den ersten kennst du: die ganze Funktion über main verschieben. Der zweite ist ein Funktionsprototyp über main: die erste Zeile der Funktion, mit einem Semikolon am Ende statt des Rumpfs:
#include <stdio.h>
void begruesse(void);
int main(void) {
begruesse();
return 0;
}
void begruesse(void) {
printf("Hallo!\n");
}Dieses Programm gibt aus:
Hallo!Der Prototyp void begruesse(void); ist eine Deklaration der Funktion. Er sagt dem Compiler: Es gibt eine Funktion begruesse, sie nimmt nichts entgegen und gibt nichts zurück, und ihre Definition kommt später. Das reicht dem Compiler, um den Aufruf zu prüfen. Der Prototyp muss zur Definition passen: derselbe Rückgabetyp, derselbe Name und dieselben Klammern. Und die Definition muss wirklich da sein: Mit einem Prototyp, aber ohne Definition läuft das Programm nicht, und die Fehlermeldung endet mit undefined symbol: begruesse, was bedeutet, dass der Rumpf von begruesse fehlt.
Warum schreibt man Prototypen? In einem langen Programm wirken die Prototypen am Anfang wie das Inhaltsverzeichnis eines Buchs: Du siehst alle Funktionen auf einen Blick, und main kann gleich danach kommen. Und du benutzt Prototypen seit der ersten Lektion, ohne es zu wissen. Die Datei stdio.h ist eine Header-Datei: Sie enthält die Prototypen von printf und anderen Funktionen der Bibliothek, der Sammlung fertiger Funktionen, die mit C mitkommt. #include <stdio.h> fügt ihren Inhalt in dein Programm ein, damit der Compiler printf kennt, bevor du es aufrufst. Genauso deklariert string.h die Funktion strlen und ctype.h die Funktion toupper.
In diesem Kurs schreiben wir meistens ganze Funktionen über main, weil es einfacher ist. Aber wenn du in einem Programm einen Prototyp siehst, weißt du, was er ist.
So schreibst du es:
Anweisungen
- 1
Das Programm lässt sich nicht kompilieren, weil
maindie Funktionzeige_titelaufruft, die darunter definiert ist. Verschiebe die Funktion nicht. Füge stattdessen ihren Prototyp übermainhinzu. Das Programm gibt dann den Titel undDrücke Start, um zu spielen.aus. - 2
Schreibe unter der Funktion
zeige_titeleine Funktionvoid zeige_abschied(void), dieDanke fürs Spielen!ausgibt, und füge ihren Prototyp übermainhinzu, unter dem ersten. - 3
Rufe am Ende von
main, vorreturn 0;,zeige_abschiedauf. Das Programm gibt aus:STERNENFLUG =========== Drücke Start, um zu spielen. Danke fürs Spielen!