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 }

Listing 7.2    In dem Beispiel vorausdeklaration_1.c wird der Compiler eine Fehlermeldung ausgeben.

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:

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 }

Listing 7.3    vorausdeklaration_2.c funktioniert jetzt ohne Probleme, weil die Funktion hallo() jetzt am Anfang als Prototyp deklariert wird.

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.