Namespaces
Variants

Function declarations

From cppreference.net

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
1) Neue (C89) Funktionsdeklaration. Diese Deklaration führt sowohl den Funktionsbezeichner selbst ein als dient auch als Funktionsprototyp für zukünftige Funktionsaufrufausdrücke , erzwingt Konvertierungen von Argumentausdrücken zu den deklarierten Parametertypen und Übersetzungszeitprüfungen für die Anzahl der Argumente.
int max(int a, int b); // declaration
int n = max(12.01, 3.14); // OK, conversion from double to int
2) (bis C23) Alte (K&R) Funktionsdefinition. Diese Deklaration führt keinen Prototypen ein und jegliche zukünftigen Funktionsaufrufausdrücke führen Standardargument-Promotions durch und rufen undefiniertes Verhalten hervor, wenn die Anzahl der Argumente nicht mit der Anzahl der Parameter übereinstimmt.
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)
3) Nicht-Prototyp-Funktionsdeklaration. Diese Deklaration führt keinen Prototyp ein (bis C23) . Eine neue Funktionsdeklarationsweise, äquivalent zu parameter-list void (seit C23) .

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