- 11/04/2016
- 3 Minuten zu lesen
-
- c
- v
- n
- M
- g
-
+1
Eine Funktionsdeklaration steht vor der Funktionsdefinition und gibt den Namen an, Rückgabetyp, Speicherklasse und andere Attribute einer Funktion. Um ein Prototyp zu sein, muss die Funktionsdeklaration auch Typen und Bezeichner für die Argumente der Funktion festlegen.
Syntax
declaration:
declaration-specifiers attribute-seqopt init-declarator-listopt ;
/* attribute-seqopt ist Microsoft-spezifisch */
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator
declarator = initializer
declarator:
pointeropt direct-declarator
direct-declarator: /* Ein Funktionsdeklarator */
direct-declarator ( parameter-type-list ) /* New-style-declarator */
direct-declarator ( identifier-listopt ) /* Obsolete-style-declarator */
Der Prototyp hat die gleiche Form wie die Funktionsdefinition, außer dass er durch ein Semikolon unmittelbar nach der schließenden Klammer beendet wird und daher keinen Körper hat. In beiden Fällen muss der Rückgabetyp mit dem in der Funktionsdefinition angegebenen Rückgabetyp übereinstimmen.
Funktionsprototypen haben die folgenden wichtigen Verwendungen:
-
Sie legen den Rückgabetyp für Funktionen fest, die andere Typen als
int
zurückgeben. Obwohl Funktionen, dieint
-Werte zurückgeben, keine Prototypen benötigen, werden Prototypen empfohlen. -
Ohne vollständige Prototypen werden Standardkonvertierungen vorgenommen, aber es wird kein Versuch unternommen, den Typ oder die Anzahl der Argumente mit der Anzahl der Parameter zu überprüfen.
-
Prototypen werden verwendet, um Zeiger auf Funktionen zu initialisieren, bevor diese Funktionen definiert werden.
-
Die Parameterliste dient zur Überprüfung der Übereinstimmung der Argumente im Funktionsaufruf mit den Parametern in der Funktionsdefinition.
Der umgewandelte Typ jedes Parameters bestimmt die Interpretation der Argumente, die der Funktionsaufruf auf den Stack legt. Eine Typinkongruenz zwischen einem Argument und einem Parameter kann dazu führen, dass die Argumente auf dem Stack falsch interpretiert 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 Bits auf dem Stack als long
-Parameter interpretiert. Dieser Fehler führt nicht nur zu Problemen 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, so dass Funktionsaufrufe, die ihrer Definition vorausgehen (oder in anderen Quelldateien vorkommen), auf Unstimmigkeiten zwischen Argumenttyp und Rückgabetyp überprüft werden können. Wenn Sie beispielsweise den static
-Speicherklassenspezifizierer in einem Prototyp angeben, müssen Sie auch die static
-Speicherklasse in der Funktionsdefinition angeben.
Komplette Parameterdeklarationen (int a
) können mit abstrakten Deklaratoren (int
) in derselben Deklaration gemischt werden. Zum Beispiel ist die folgende Deklaration legal:
int add( int a, int );
Der Prototyp kann sowohl den Typ als auch einen Bezeichner für jeden Ausdruck enthalten, der als Argument übergeben wird. Solche Bezeichner haben jedoch nur bis zum Ende der Deklaration Gültigkeit. Der Prototyp kann auch die Tatsache widerspiegeln, dass die Anzahl der Argumente variabel ist, oder dass keine Argumente übergeben werden. Ohne eine solche Liste können Unstimmigkeiten nicht aufgedeckt werden, so dass der Compiler diesbezüglich keine Diagnosemeldungen erzeugen kann. Weitere Informationen zur Typüberprüfung finden Sie unter Argumente.
Der Prototypbereich im Microsoft C-Compiler ist jetzt ANSI-konform, wenn mit der Compileroption /Za kompiliert wird. Das bedeutet, dass, wenn Sie ein struct
– oder union
-Tag innerhalb eines Prototyps deklarieren, das Tag in diesem Bereich und nicht im globalen Bereich eingegeben wird. Wenn Sie zum Beispiel mit /Za kompilieren, um die ANSI-Konformität zu gewährleisten, können Sie diese Funktion nicht aufrufen, ohne einen Fehler bei der Typübereinstimmung zu erhalten:
void func1( struct S * );
Um Ihren Code zu korrigieren, definieren oder deklarieren Sie struct
oder union
im globalen Bereich vor dem Funktionsprototyp:
struct S;void func1( struct S * );
Unter /Ze wird das Tag weiterhin im globalen Bereich eingegeben.
Siehe auch
Funktionen