7.3 Funktionsdeklaration (Vorausdeklaration)
Sie können neue Funktionen auch hinter den aufrufenden Funktionen definieren – also erst die main()-Funktion erstellen und dahinter die Funktionsdefinition. Da allerdings der Programmcode von oben nach unten abgearbeitet wird, kann in diesem Fall der Compiler zum Zeitpunkt des Aufrufes die entsprechende Funktion nicht kennen. Es folgt ein Beispiel dafür, wie es nicht geht:
00 // Kapitel7/vorausdeklaration_1.c
01 #include <stdio.h>
02 int main(void) {
03 printf("Vor der Funktion\n");
04 hallo(); // Fehler/Warnung: hallo() unbekannt
05 printf("Nach der Funktion\n");
06 return 0;
07 }
08 void hallo(void) {
09 printf("In der Funktion\n");
10 }
Wenn der Compiler in Zeile (04) die Funktion hallo() sieht, ist diese eigentlich noch gar nicht bekannt, weil sie erst ab Zeile (08) definiert wird. Für gewöhnlich sollten Sie in diesem Fall schon während der Übersetzung eine Warn- bzw. Fehlermeldung erhalten haben, wie z. B. »unknown reference to hallo«. Wenn sich das Listing in diesem Beispiel trotzdem ausführen lässt, liegt es daran, dass der Compiler hier eine implizite Umwandlung des Rückgabewertes nach int durchführt, wenn eine Funktion vorher nicht deklariert oder definiert wurde. Sobald Sie eine Funktion mit einem anderen Rückgabewert als void oder int verwendet haben, klappt es auch nicht mehr mit der impliziten Konvertierung des Rückgabewertes.
Um ein fehlerhaftes Verhalten des Programms von vornherein zu vermeiden, haben Sie zwei Möglichkeiten:
-
Sie definieren die Funktion vor dem ersten Aufruf, wie Sie dies z. B. im Listing vorausdeklaration_1.c in diesem Kapitel gemacht haben.
-
Sie deklarieren die Funktion bzw. genauer den Funktionsprototyp vor dem ersten Aufruf. Bei einer Deklaration müssen Sie die Funktion nicht vollständig definieren, sondern nur den Funktionskopf angeben und mit einem Semikolon abschließen. So weiß der Compiler schon vor der Ausführung, welchen erforderlichen Datentyp dieser für den Rückgabewert und den Parameter verwenden muss. Mehr Informationen sind für ihn zunächst nicht nötig. Die Definition der Funktion kann sich dann an einer beliebigen anderen Stelle (für gewöhnlich in einer anderen Quelldatei) befinden. Eine solche Deklaration wird auch als Vorausdeklaration (Forward-Deklaration) bezeichnet.
Hierzu nochmals das Listing vorausdeklaration_1.c, nur dieses Mal mit einer nötigen Vorausdeklaration in Zeile (02), wie wir es soeben beschrieben haben:
00 // Kapitel7/vorausdeklaration_2.c
01 #include <stdio.h>
02 void hallo(void); // Funktionsprototyp
03 int main(void) {
04 printf("Vor der Funktion\n");
05 hallo(); // Funktionsaufruf
06 printf("Nach der Funktion\n");
07 return 0;
08 }
09 // Funktionsdefinition
10 void hallo(void) {
11 printf("In der Funktion\n");
12 }
Natürlich ist der Zweck einer Vorausdeklaration eines solchen Funktionsprototyps wie in Zeile (02) nicht ausschließlich der, eine Funktion in demselben Quellcode hinter der main()-Funktion zu definieren. In der Praxis werden solche Deklarationen von Funktionsprototypen eher dann verwendet, wenn es darum geht, ihren Quellcode in mehrere einzelne Module aufzuteilen. Hierbei wird häufig die Deklaration (Funktionsprototyp) wie in Zeile (02) und die Definition wie in den Zeilen (09) bis (12) jeweils in eine separate Header- und Quellcodedatei aufgeteilt. Auch in großen Projekten macht es sicherlich oft Sinn, erst einmal leere Funktionsrümpfe zu definieren, und diese anschließend Stück für Stück mit Leben zu füllen. In diesem Fall haben Sie, wenn Sie dann im Team arbeiten, sehr schnell ein laufendes Programm, das Sie Stück für Stück testen können.