Freigeben über


Funktionsprototypen

Eine Funktionsdeklaration ist der Funktionsdefinition vorangestellt und gibt den Namen, Rückgabetyp, die Speicherklasse und andere Attribute einer Funktion an. Um als Prototyp zu fungieren, muss die Funktionsdeklaration auch Typen und Bezeichner für die Argumente der Funktion festlegen.

Syntax

declaration:
declaration-specifiersattribute-seqoptinit-declarator-listopt;

/* attribute-seqopt ist Microsoft-spezifisch */

declaration-specifiers:
storage-class-specifierdeclaration-specifiersopt
type-specifierdeclaration-specifiersopt
type-qualifierdeclaration-specifiersopt

init-declarator-list:
init-declarator
init-declarator-list , init-declarator

init-declarator:
declarator
declarator = initializer

declarator:
pointeroptdirect-declarator

direct-declarator: /* Ein Funktionsdeklarator */
direct-declarator(parameter-type-list) /* Deklarator im neuen Format */
direct-declarator(identifier-listopt) /* Deklarator im veralteten Format */

Der Prototyp hat das gleiche Format wie die Funktionsdefinition. Allerdings wird er mit einem Semikolon unmittelbar nach der schließenden Klammer beendet und enthält dementsprechend keinen Textkörper. In jedem Fall muss der Rückgabetyp dem Rückgabetyp entsprechen, der in der Funktionsdefinition angegeben wird.

Funktionsprototypen haben die folgenden wichtigen Verwendungen:

  • Sie legen den Rückgabetyp für Funktionen fest, die andere Typen als int zurückgeben. Obwohl Funktionen, die int -Werte zurückgeben, keine Prototypen erfordern, werden Prototypen empfohlen.

  • Ohne vollständige Prototypen werden Standardkonvertierungen ausgeführt, es wird jedoch nicht versucht, Typ oder Anzahl der Argumente anhand der Anzahl der Parameter zu überprüfen.

  • Prototypen werden verwendet, um Zeiger auf Funktionen zu initialisieren, bevor diese Funktionen definiert werden.

  • Die Parameterliste wird verwendet, um zu überprüfen, ob die Argumente im Funktionsaufruf mit den Parametern in der Funktionsdefinition übereinstimmen.

Der konvertierte Typ jedes Parameters bestimmt die Interpretation der Argumente, die der Funktionsaufruf auf dem Stapel ablegt. Ein Typenkonflikt zwischen einem Parameter und einem Argument kann verursachen, dass Argumente auf dem Stapel fehlinterpretiert werden. Wenn beispielsweise auf einem 16-Bit-Computer ein 16-Bit-Zeiger als Argument übergeben und dann als long -Parameter deklariert wird, werden die ersten 32 Bit im Stapel als long -Parameter interpretiert. Dieser Fehler verursacht nicht nur Probleme mit dem long-Parameter, sondern auch mit allen nachfolgenden Parametern. Sie können Fehler dieser Art erkennen, indem Sie vollständige Funktionsprototypen für alle Funktionen deklarieren.

Ein Prototyp legt die Attribute einer Funktion fest. Anschließend können Funktionsaufrufe, die der Funktionsdefinition vorangehen (oder in anderen Quelldateien auftreten), auf Konflikte mit Argument- und Rückgabetypen überprüft werden. Wenn Sie beispielsweise den Speicherklassenspezifizierer static in einem Prototyp angeben, müssen Sie die static -Speicherklasse auch in der Funktionsdefinition angeben.

Vollständige Parameterdeklarationen (int a) können mit abstrakten Deklaratoren (int) in der gleichen Deklaration kombiniert werden. Die folgende Deklaration ist beispielsweise gültig:

int add( int a, int );

Der Prototyp kann sowohl den Typ als auch den Bezeichner für jeden Ausdruck beinhalten, der als Argument übergeben wird. Solche Bezeichner befinden sich jedoch nur bis zum Ende der Deklaration im Gültigkeitsbereich. Der Prototyp reflektiert auch die Tatsache, dass die Anzahl der Argumente variabel ist oder dass keine Argumente übergeben werden. Ohne eine solche Liste können Konflikte nicht aufgedeckt werden, sodass der Compiler keine entsprechenden Diagnosemeldungen generieren kann. Weitere Informationen zur Typüberprüfung finden Sie unter Argumente.

Der Prototypbereich im Microsoft C-Compiler ist beim Kompilieren mit der Compileroption /Za jetzt ANSI-konform. Wenn Sie ein struct - oder union -Tag in einem Prototyp deklarieren, wird das Tag in diesem Gültigkeitsbereich eingetragen, nicht im globalen Gültigkeitsbereich. Zum Beispiel können Sie bei der Kompilierung mit /Za für ANSI-Konformität diese Funktion nicht aufrufen, ohne einen Typenkonfliktfehler zu verursachen:

void func1( struct S * );

Definieren oder deklarieren Sie struct oder union im globalen Bereich vor dem Funktionsprototyp, um den Code zu korrigieren:

struct S;
void func1( struct S * );

Unter /Ze wird das Tag weiterhin im globalen Gültigkeitsbereich eingegeben.

Siehe auch

Funktionen