Namensräume
Varianten
Aktionen

Funktionsdeklarationen

Von cppreference.com
< c‎ | Sprache

Eine Funktionsdeklaration führt einen Bezeichner ein, der eine Funktion bezeichnet, und gibt optional die Typen der Funktionsparameter an (das Prototyp). Funktionsdeklarationen (im Gegensatz zu Definitions) können im Block-Scope sowie im Datei-Scope erscheinen.

Inhalt

[bearbeiten] Syntax

In der Deklarationsgrammatik einer Funktionsdeklaration bezeichnet die Sequenz von type-specifier, 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 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)

wobei

noptr-declarator - jeder Deklarator außer einem nicht geklammerten Zeigerdeklarator. Der Bezeichner, der in diesem Deklarator enthalten ist, ist der Bezeichner, der zum Funktionsbezeichner wird.
parameter-liste - entweder das einzelne Schlüsselwort void oder eine durch Kommas getrennte Liste von Parametern, die mit einem Ellipsenparameter enden kann
identifier-list - durch Kommas getrennte 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, die auf den Funktionstyp angewendet werden
1) Deklaration einer Funktion im neuen Stil (C89). Diese Deklaration führt sowohl den Funktionsbezeichner selbst ein als auch dient als Funktionsprototyp für alle zukünftigen Funktionsaufrufausdrücke und erzwingt Konvertierungen von Argumentausdrücken in die deklarierten Parametertypen und Kompilierungsprü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) Funktionsdefinition im alten Stil (K&R). Diese Deklaration führt keinen Prototyp ein und alle zukünftigen Funktionsaufrufausdrücke führen Standard-Argumentpromotionen durch und rufen undefiniertes Verhalten auf, 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 Funktionsdeklaration, die äquivalent zur parameter-list void ist(seit C23).

[bearbeiten] 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 zur Konstruktion des Funktionstyps auf seine unqualifizierte Version angepasst.

void f(char *s);                    // return type is void
int sum(int a, int b);              // return type of sum is int.
int (*foo(const void *p))[3];       // return type is pointer to array of 3 int
 
double const bar(void);             // declares function of type double(void)
double (*barp)(void) = bar;         // OK: barp is a pointer to double(void)
double const (*barpc)(void) = barp; // OK: barpc is also a pointer to double(void)

Funktionsdeklaratoren können mit anderen Deklaratoren kombiniert werden, solange sie ihre Typspezifizierer und Qualifizierer teilen können

int f(void), *fip(), (*pfi)(), *ap[3]; // declares two functions and two objects
inline int g(int), n; // Error: inline qualifier is for functions only
typedef int array_t[3];
array_t a, h(); // Error: array type cannot be a return type for a function

Wenn eine Funktionsdeklaration außerhalb einer Funktion erscheint, hat der von ihr eingeführte Bezeichner Dateigeltungsbereich und externe Bindung, es sei denn, static wird verwendet oder eine frühere statische Deklaration ist sichtbar. Wenn die Deklaration innerhalb einer anderen Funktion auftritt, hat der Bezeichner Blockgeltungsbereich (und auch entweder interne oder externe Bindung).

int main(void)
{
    int f(int); // external linkage, block scope
    f(1); // definition needs to be available somewhere in the program
}

Die Parameter in einer Deklaration, die nicht Teil einer Funktionsdefinition ist(bis C23) müssen nicht benannt werden

int f(int, int); // declaration
// int f(int, int) { return 7; } // Error: parameters must be named in definitions
// This definition is allowed since C23

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); // also OK
// int f(int, double) { return 1; } // Error: definition must name parameters
// This definition is allowed since C23
  • der einzige Speicherklassenspezifizierer, der für Parameter zulässig ist, ist register, und er wird in Funktionsdeklarationen, die keine Definitionen sind, ignoriert
int f(static int x); // Error
int f(int [static 10]); // OK (array index static is not a storage class specifier)
  • jeder Parameter vom Array-Typ wird an den entsprechenden Zeigertyp angepasst, der qualifiziert sein kann, wenn sich Qualifizierer zwischen den eckigen Klammern des Array-Deklarators befinden(seit C99)
int f(int[]); // declares int f(int*)
int g(const int[10]); // declares int g(const int*)
int h(int[const volatile]); // declares int h(int * const volatile)
int x(int[*]); // declares int x(int*)
  • jeder Parameter vom Funktionstyp wird an den entsprechenden Zeigertyp angepasst
int f(char g(double)); // declares int f(char (*g)(double))
int h(int(void)); // declares int h(int (*)(void))
int f(int, ...);
  • Parameter dürfen nicht den Typ void haben (können aber den Typ Zeiger auf void haben). Die spezielle Parameterliste, die ausschließlich aus dem Schlüsselwort void besteht, wird zur Deklaration von Funktionen verwendet, die keine Parameter entgegennehmen.
int f(void); // OK
int g(void x); // Error
  • jeder Bezeichner, der in einer Parameterliste vorkommt, die als typedef-Name oder als Parametername behandelt werden kann, wird als typedef-Name behandelt: int f(size_t, uintptr_t) wird als Deklarator im neuen Stil für eine Funktion geparst, die zwei unbenannte Parameter vom Typ size_t und uintptr_t entgegennimmt, nicht als Deklarator im alten Stil, der die Definition einer Funktion beginnt, die zwei Parameter mit den Namen "size_t" und "uintptr_t" entgegennimmt
  • Parameter dürfen einen unvollständigen Typ haben und können die VLA-Notation [*] verwenden(seit C99) (außer dass in einer Funktionsdefinition die Parametertypen nach Array-zu-Zeiger- und Funktions-zu-Zeiger-Anpassung vollständig sein müssen)

Attribut-Spezifizierer-Sequenzen können auch auf Funktionsparameter angewendet werden.

(seit C23)

Siehe Funktionsaufrufoperator für weitere Details zu den Mechanismen eines Funktionsaufrufs und return für die Rückgabe aus Funktionen.

[bearbeiten] Anmerkungen

Im Gegensatz zu C++ haben die Deklaratoren f() und f(void) unterschiedliche Bedeutungen: Der Deklarator f(void) ist ein Deklarator im neuen Stil (mit Prototyp), der eine Funktion deklariert, die keine Parameter annimmt. Der Deklarator f() ist ein Deklarator, der eine Funktion deklariert, die eine *unbestimmte* Anzahl von Parametern annimmt (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 is a function type int(int, int)
p f; // declares int f(int, int)

In C89 war specifiers-and-qualifiers optional, und wenn es weggelassen wurde, wurde der Rückgabetyp der Funktion standardmäßig als int angenommen (möglicherweise durch den declarator ergänzt).

*f() { // function returning int*
   return NULL;
}
(bis C99)

[bearbeiten] Fehlerberichte

Die folgenden verhaltensändernden Defect Reports wurden rückwirkend auf zuvor veröffentlichte C-Standards angewendet.

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
DR 423 C89 der Rückgabetyp könnte qualifiziert sein der Rückgabetyp wird implizit disqualifiziert

[bearbeiten] Referenzen

  • 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)

[bearbeiten] Siehe auch

C++ Dokumentation für Funktionsdeklaration