Function declarations
Eine Funktionsdeklaration führt einen Identifier ein, der eine Funktion bezeichnet und optional die Typen der Funktionsparameter spezifiziert (den Prototyp ). Funktionsdeklarationen (im Gegensatz zu Definitionen ) können sowohl im Blockbereich als auch im Dateibereich erscheinen.
Inhaltsverzeichnis |
Syntax
In der Deklarationsgrammatik einer Funktionsdeklaration bezeichnet die type-specifier -Sequenz, möglicherweise modifiziert durch den Deklarator, den Rückgabetyp (der jeder Typ außer Array- oder Funktionstyp sein kann), und der declarator hat eine von drei (until C23) zwei (since C23) Formen:
noptr-declarator
(
parameter-list
)
attr-spec-seq
(optional)
|
(1) | ||||||||
noptr-declarator
(
identifier-list
)
attr-spec-seq
(optional)
|
(2) | (bis C23) | |||||||
noptr-declarator
(
)
attr-spec-seq
(optional)
|
(3) | ||||||||
wo
| noptr-declarator | - | jeder Deklarator außer ungeklammerter Zeigerdeklarator. Der in diesem Deklarator enthaltene Bezeichner ist der Bezeichner, der zum Funktionsdesignator wird. |
| parameter-list | - | entweder das einzelne Schlüsselwort void oder eine kommagetrennte Liste von Parametern , die mit einem Ellipsenparameter enden kann |
| identifier-list | - | kommagetrennte Liste von Bezeichnern, nur möglich, wenn dieser Deklarator als Teil einer Funktionsdefinition im alten Stil verwendet wird |
| attr-spec-seq | - | (C23) eine optionale Liste von Attributen , angewendet auf den Funktionstyp |
int max(int a, int b); // declaration int n = max(12.01, 3.14); // OK, conversion from double to int
int max(a, b) int a, b; // definition expects ints; the second call is undefined { return a > b ? a : b; } int n = max(true, (char)'a'); // calls max with two int args (after promotions) int n = max(12.01f, 3.14); // calls max with two double args (after promotions)
Erklärung
Der Rückgabetyp der Funktion, bestimmt durch den Typspezifizierer in specifiers-and-qualifiers und möglicherweise modifiziert durch den declarator wie üblich in Deklarationen , muss ein Nicht-Array-Objekttyp oder der Typ void sein. Wenn die Funktionsdeklaration keine Definition ist, kann der Rückgabetyp unvollständig sein. Der Rückgabetyp kann nicht cvr-qualifiziert sein: Jeder qualifizierte Rückgabetyp wird für die Konstruktion des Funktionstyps auf seine unqualifizierte Version angepasst.
void f(char *s); // Rückgabetyp ist void int sum(int a, int b); // Rückgabetyp von sum ist int. int (*foo(const void *p))[3]; // Rückgabetyp ist Zeiger auf Array von 3 int double const bar(void); // deklariert Funktion vom Typ double(void) double (*barp)(void) = bar; // OK: barp ist ein Zeiger auf double(void) double const (*barpc)(void) = barp; // OK: barpc ist ebenfalls ein Zeiger auf double(void)
Funktionsdeklaratoren können mit anderen Deklaratoren kombiniert werden, solange sie ihre Typspezifizierer und Qualifizierer gemeinsam nutzen können
int f(void), *fip(), (*pfi)(), *ap[3]; // deklariert zwei Funktionen und zwei Objekte inline int g(int), n; // Fehler: inline-Qualifizierer gilt nur für Funktionen typedef int array_t[3]; array_t a, h(); // Fehler: Array-Typ kann kein Rückgabetyp für eine Funktion sein
Wenn eine Funktionsdeklaration außerhalb einer Funktion erscheint, hat der Bezeichner, den sie einführt, Dateigültigkeitsbereich und externe Bindung , es sei denn, static wird verwendet oder eine frühere static-Deklaration ist sichtbar. Wenn die Deklaration innerhalb einer anderen Funktion auftritt, hat der Bezeichner Blockgültigkeitsbereich (und ebenfalls entweder interne oder externe Bindung).
int main(void) { int f(int); // externer Linkage, Block-Gültigkeitsbereich f(1); // Definition muss irgendwo im Programm verfügbar sein }
Die Parameter in einer Deklaration die nicht Teil einer Funktionsdefinition (bis C23) müssen nicht benannt werden:
int f(int, int); // Deklaration // int f(int, int) { return 7; } // Fehler: Parameter müssen in Definitionen benannt werden // Diese Definition ist seit C23 erlaubt
Jeder Parameter in einer parameter-list ist eine Deklaration , die eine einzelne Variable einführt, mit den folgenden zusätzlichen Eigenschaften:
- der Bezeichner im Deklarator ist optional (außer wenn diese Funktionsdeklaration Teil einer Funktionsdefinition ist) (bis C23)
int f(int, double); // OK int g(int a, double b); // ebenfalls OK // int f(int, double) { return 1; } // Fehler: Definition muss Parameter benennen // Diese Definition ist seit C23 erlaubt
- der einzige Speicherklassenspezifizierer , der für Parameter erlaubt ist, ist register , und er wird in Funktionsdeklarationen, die keine Definitionen sind, ignoriert
int f(static int x); // Fehler int f(int [static 10]); // OK (Array-Index-static ist kein Speicherklassen-Spezifizierer)
- Jeder Parameter vom Array-Typ wird zum entsprechenden Zeigertyp angepasst , der qualifiziert sein kann, falls Qualifizierer zwischen den eckigen Klammern des Array-Deklarators vorhanden sind (seit C99)
int f(int[]); // deklariert int f(int*) int g(const int[10]); // deklariert int g(const int*) int h(int[const volatile]); // deklariert int h(int * const volatile) int x(int[*]); // deklariert int x(int*)
- Jeder Parameter vom Funktionstyp wird zum entsprechenden Zeigertyp angepasst
int f(char g(double)); // deklariert int f(char (*g)(double)) int h(int(void)); // deklariert int h(int (*)(void))
-
Die Parameterliste kann mit
, ...oder als...(seit C23) enden, siehe variadic functions für Details.
int f(int, ...);
- Parameter können nicht den Typ void haben (können jedoch den Typ Zeiger auf void haben). Die spezielle Parameterliste, die ausschließlich aus dem Schlüsselwort void besteht, wird verwendet, um Funktionen zu deklarieren, die keine Parameter entgegennehmen.
int f(void); // Korrekt int g(void x); // Fehler
- Jeder Bezeichner, der in einer Parameterliste erscheint und entweder als Typname oder als Parametername behandelt werden könnte, wird als Typname behandelt: int f ( size_t , uintptr_t ) wird als New-Style-Deklarator für eine Funktion mit zwei unbenannten Parametern vom Typ size_t und uintptr_t geparst, nicht als Old-Style-Deklarator, der die Definition einer Funktion mit zwei Parametern namens " size_t " und " uintptr_t " einleitet.
- Parameter können unvollständige Typen haben und können die VLA-Notation [ * ] (seit C99) verwenden (außer dass in einer Funktionsdefinition die Parametertypen nach Array-zu-Zeiger- und Funktion-zu-Zeiger-Anpassung vollständig sein müssen).
|
Attributspezifizierer-Sequenzen können auch auf Funktionsparameter angewendet werden. |
(seit C23) |
Weitere Einzelheiten zur Funktionsweise eines Funktionsaufrufs finden Sie unter Funktionsaufruf-Operator und Informationen zum Verlassen von Funktionen unter return .
Hinweise
|
Im Gegensatz zu C++ haben die Deklaratoren f ( ) und f ( void ) unterschiedliche Bedeutung: Der Deklarator f ( void ) ist ein neuer (Prototyp-)Deklarator, der eine Funktion deklariert, die keine Parameter akzeptiert. Der Deklarator f ( ) ist ein Deklarator, der eine Funktion deklariert, die eine nicht spezifizierte Anzahl von Parametern akzeptiert (sofern nicht in einer Funktionsdefinition verwendet). int f(void); // declaration: takes no parameters int g(); // declaration: takes unknown parameters int main(void) { f(1); // compile-time error g(2); // undefined behavior } int f(void) { return 1; } // actual definition int g(a,b,c,d) int a,b,c,d; { return 2; } // actual definition |
(bis C23) |
Im Gegensatz zu einer Funktionsdefinition kann die Parameterliste von einem typedef geerbt werden
typedef int p(int q, int r); // p ist ein Funktionstyp int(int, int) p f; // deklariert int f(int, int)
|
In C89, specifiers-and-qualifiers war optional, und wenn weggelassen, wurde der Rückgabetyp der Funktion standardmäßig auf int gesetzt (möglicherweise durch den declarator geändert). *f() { // function returning int* return NULL; } |
(bis C99) |
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| DR 423 | C89 | der Rückgabetyp könnte qualifiziert sein | der Rückgabetyp wird implizit disqualifiziert |
Referenzen
- C23-Standard (ISO/IEC 9899:2024):
-
- 6.7.7.4 Funktionsdeklaratoren (einschließlich Prototypen) (S: 130-132)
- C17-Standard (ISO/IEC 9899:2018):
-
- 6.7.6.3 Funktionsdeklaratoren (einschließlich Prototypen) (S: 96-98)
- C11-Standard (ISO/IEC 9899:2011):
-
- 6.7.6.3 Funktionsdeklaratoren (einschließlich Prototypen) (S: 133-136)
- C99-Standard (ISO/IEC 9899:1999):
-
- 6.7.5.3 Funktionsdeklaratoren (einschließlich Prototypen) (S: 118-121)
- C89/C90 Standard (ISO/IEC 9899:1990):
-
- 3.5.4.3 Funktionsdeklaratoren (einschließlich Prototypen)
Siehe auch
|
C++ Dokumentation
für
Funktionsdeklaration
|