Function definitions
Eine Funktionsdefinition verknüpft den Funktionsrumpf (eine Folge von Deklarationen und Anweisungen) mit dem Funktionsnamen und der Parameterliste. Im Gegensatz zur Funktionsdeklaration sind Funktionsdefinitionen nur im Dateigültigkeitsbereich erlaubt (es gibt keine geschachtelten Funktionen).
C unterstützt zwei verschiedene Formen von Funktionsdefinitionen:
| attr-spec-seq (optional) specifiers-and-qualifiers parameter-list-declarator function-body | (1) | ||||||||
| specifiers-and-qualifiers identifier-list-declarator declaration-list function-body | (2) | (bis C23) | |||||||
wo
| attr-spec-seq | - | (C23) eine optionale Liste von Attributen , angewendet auf die Funktion |
| specifiers-and-qualifiers | - |
eine Kombination aus
|
| parameter-list-declarator | - | ein Deklarator für einen Funktionstyp, der eine Parameterliste verwendet, um Funktionsparameter zu bezeichnen |
| identifier-list-declarator | - | ein Deklarator für einen Funktionstyp, der eine Bezeichnerliste verwendet, um Funktionsparameter zu bezeichnen |
| declaration-list | - | eine Folge von Deklarationen, die jeden Bezeichner in identifier-list-declarator deklarieren. Diese Deklarationen können keine Initialisierer verwenden und der einzige erlaubte Speicherklassenspezifizierer ist register . |
| function-body | - | ein Verbundstatement , also eine in geschweiften Klammern eingeschlossene Folge von Deklarationen und Anweisungen, die bei jedem Aufruf dieser Funktion ausgeführt wird |
int max(int a, int b) { return a>b?a:b; } double g(void) { return 0.1; }
int max(a, b) int a, b; { return a>b?a:b; } double g() { return 0.1; }
Inhaltsverzeichnis |
Erklärung
Wie bei Funktionsdeklarationen muss der Rückgabetyp der Funktion, bestimmt durch den Typspezifizierer in specifiers-and-qualifiers und möglicherweise modifiziert durch den declarator wie üblich in Deklarationen , ein vollständiger Nicht-Array-Objekttyp oder der Typ void sein. Wenn der Rückgabetyp cvr-qualifiziert wäre, wird er für die Konstruktion des Funktionstyps auf seine unqualifizierte Version angepasst.
Wie bei Funktionsdeklarationen werden die Typen der Parameter von Funktionen zu Zeigern und von Arrays zu Zeigern angepasst, um den Funktionstyp zu konstruieren, und die Top-Level-cvr-Qualifizierer aller Parametertypen werden für die Bestimmung des kompatiblen Funktionstyps ignoriert.
|
Im Gegensatz zu Funktionsdeklarationen sind unbenannte formale Parameter nicht zulässig (andernfalls gäbe es Konflikte bei alten (K&R) Funktionsdefinitionen). Sie müssen benannt werden, selbst wenn sie innerhalb der Funktion nicht verwendet werden. Die einzige Ausnahme ist die spezielle Parameterliste ( void ) . |
(bis C23) |
|
Formale Parameter können in Funktionsdefinitionen unbenannt sein, da alte (K&R) Funktionsdefinitionen entfernt wurden. Unbenannte Parameter sind innerhalb des Funktionskörpers nicht über ihren Namen zugreifbar. |
(seit C23) |
int f(int, int); // Deklaration // int f(int, int) { return 7; } // Fehler bis C23, OK seit C23 int f(int a, int b) { return 7; } // Definition int g(void) { return 8; } // OK: void deklariert keinen Parameter
Im Funktionsrumpf ist jeder benannte Parameter ein lvalue -Ausdruck; sie haben automatische Speicherdauer und Blockgültigkeitsbereich . Die Speicheranordnung der Parameter (oder ob sie überhaupt im Speicher abgelegt werden) ist nicht spezifiziert: Sie ist Teil der Aufrufkonvention .
int main(int ac, char **av) { ac = 2; // Parameter sind Lvalues av = (char *[]){"abc", "def", NULL}; f(ac, av); }
Weitere Einzelheiten zur Funktionsweise eines Funktionsaufrufs finden Sie unter Funktionsaufruf-Operator und Informationen zum Verlassen von Funktionen unter return .
__func__In jedem Funktionsrumpf ist die spezielle vordefinierte Variable __func__ mit Blockgültigkeit und statischer Speicherdauer verfügbar, als wäre sie unmittelbar nach der öffnenden Klammer definiert durch: static const char __func__[] = "function name"; Dieser spezielle Bezeichner wird manchmal in Kombination mit den vordefinierten Makrokonstanten __FILE__ und __LINE__ verwendet, zum Beispiel durch assert . |
(seit C99) |
Hinweise
Die Argumentliste muss explizit im Deklarator vorhanden sein, sie kann nicht von einem typedef geerbt werden
typedef int p(int q, int r); // p ist ein Funktionstyp int(int, int) p f { return q + r; } // Fehler
|
In C89 war specifiers-and-qualifiers optional, und wenn es weggelassen wurde, war der Rückgabetyp der Funktion standardmäßig int (möglicherweise geändert durch den declarator ). Zusätzlich erforderte die alte Definitionsweise keine Deklaration für jeden Parameter in declaration-list . Jeder Parameter, dessen Deklaration fehlte, hatte den Typ int max(a, b) // a and b have type int, return type is int { return a>b?a:b; } |
(bis C99) |
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C-Standards angewendet.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| DR 423 | C89 | der Rückgabetyp könnte qualifiziert sein | der Rückgabetyp wird implizit disqualifiziert |
Referenzen
- C17-Standard (ISO/IEC 9899:2018):
-
- 6.9.1 Funktionsdefinitionen (S: 113-115)
- C11-Standard (ISO/IEC 9899:2011):
-
- 6.9.1 Function definitions (p: 156-158)
- C99-Standard (ISO/IEC 9899:1999):
-
- 6.9.1 Funktionsdefinitionen (S: 141-143)
- C89/C90-Standard (ISO/IEC 9899:1990):
-
- 3.7.1 Funktionsdefinitionen
Siehe auch
|
C++ Dokumentation
für
Funktionsdefinition
|