Function declarations
Une déclaration de fonction introduit un identifiant qui désigne une fonction et, optionnellement, spécifie les types des paramètres de la fonction (le prototype ). Les déclarations de fonctions (contrairement aux définitions ) peuvent apparaître au niveau bloc ainsi qu'au niveau fichier.
Table des matières |
Syntaxe
Dans la grammaire de déclaration d'une déclaration de fonction, la séquence type-specifier , éventuellement modifiée par le déclarateur, désigne le type de retour (qui peut être n'importe quel type autre qu'un type tableau ou fonction), et le declarator a l'une des trois (jusqu'en C23) deux (depuis C23) formes :
noptr-declarator
(
parameter-list
)
attr-spec-seq
(optionnel)
|
(1) | ||||||||
noptr-declarator
(
identifier-list
)
attr-spec-seq
(optionnel)
|
(2) | (jusqu'en C23) | |||||||
noptr-declarator
(
)
attr-spec-seq
(optionnel)
|
(3) | ||||||||
où
| noptr-declarator | - | tout déclarateur sauf un déclarateur de pointeur non parenthésé. L'identifiant contenu dans ce déclarateur est celui qui devient le désignateur de fonction. |
| parameter-list | - | soit le mot-clé unique void soit une liste séparée par des virgules de paramètres , qui peut se terminer par un paramètre ellipsis |
| identifier-list | - | liste séparée par des virgules d'identifiants, uniquement possible si ce déclarateur est utilisé comme partie d'une définition de fonction de style ancien |
| attr-spec-seq | - | (C23) une liste optionnelle d' attributs , appliquée au type de fonction |
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)
Explication
Le type de retour de la fonction, déterminé par le spécificateur de type dans specifiers-and-qualifiers et éventuellement modifié par le declarator comme d'habitude dans les déclarations , doit être un type d'objet non-tableau ou le type void . Si la déclaration de fonction n'est pas une définition, le type de retour peut être incomplet . Le type de retour ne peut pas être qualifié cvr : tout type de retour qualifié est ajusté à sa version non qualifiée pour la construction du type de fonction.
void f(char *s); // type de retour est void int sum(int a, int b); // type de retour de sum est int int (*foo(const void *p))[3]; // type de retour est pointeur vers tableau de 3 int double const bar(void); // déclare une fonction de type double(void) double (*barp)(void) = bar; // OK : barp est un pointeur vers double(void) double const (*barpc)(void) = barp; // OK : barpc est aussi un pointeur vers double(void)
Les déclarateurs de fonction peuvent être combinés avec d'autres déclarateurs tant qu'ils peuvent partager leurs spécificateurs de type et qualificateurs
int f(void), *fip(), (*pfi)(), *ap[3]; // déclare deux fonctions et deux objets inline int g(int), n; // Erreur : le qualificateur inline est réservé aux fonctions uniquement typedef int array_t[3]; array_t a, h(); // Erreur : un type tableau ne peut pas être un type de retour pour une fonction
Si une déclaration de fonction apparaît en dehors de toute fonction, l'identifiant qu'elle introduit a une portée de fichier et une liaison externe , sauf si static est utilisé ou si une déclaration static antérieure est visible. Si la déclaration se produit à l'intérieur d'une autre fonction, l'identifiant a une portée de bloc (et également soit une liaison interne soit externe).
int main(void) { int f(int); // liaison externe, portée de bloc f(1); // la définition doit être disponible quelque part dans le programme }
Les paramètres dans une déclaration qui ne fait pas partie d'une définition de fonction (jusqu'à C23) n'ont pas besoin d'être nommés :
int f(int, int); // déclaration // int f(int, int) { return 7; } // Erreur : les paramètres doivent être nommés dans les définitions // Cette définition est autorisée depuis C23
Chaque paramètre dans une parameter-list est une déclaration qui introduit une variable unique, avec les propriétés supplémentaires suivantes :
- l'identifiant dans le déclarateur est facultatif (sauf si cette déclaration de fonction fait partie d'une définition de fonction) (jusqu'à C23)
int f(int, double); // OK int g(int a, double b); // également OK // int f(int, double) { return 1; } // Erreur : la définition doit nommer les paramètres // Cette définition est autorisée depuis C23
- le seul spécificateur de classe de stockage autorisé pour les paramètres est register , et il est ignoré dans les déclarations de fonctions qui ne sont pas des définitions
int f(static int x); // Erreur int f(int [static 10]); // OK (le static d'index de tableau n'est pas un spécificateur de classe de stockage)
- tout paramètre de type tableau est ajusté au type pointeur correspondant , qui peut être qualifié s'il existe des qualificateurs entre les crochets du déclarateur de tableau (depuis C99)
int f(int[]); // déclare int f(int*) int g(const int[10]); // déclare int g(const int*) int h(int[const volatile]); // déclare int h(int * const volatile) int x(int[*]); // déclare int x(int*)
- tout paramètre de type fonction est ajusté vers le type pointeur correspondant
int f(char g(double)); // déclare int f(char (*g)(double)) int h(int(void)); // déclare int h(int (*)(void))
-
la liste de paramètres peut se terminer par
, ...ou être...(depuis C23) , voir les fonctions variadiques pour plus de détails.
int f(int, ...);
- les paramètres ne peuvent pas avoir le type void (mais peuvent avoir le type pointeur vers void). La liste de paramètres spéciale qui consiste entièrement en le mot-clé void est utilisée pour déclarer des fonctions qui ne prennent aucun paramètre.
int f(void); // Correct int g(void x); // Erreur
- tout identifiant apparaissant dans une liste de paramètres qui pourrait être traité comme un nom de typedef ou comme un nom de paramètre est traité comme un nom de typedef : int f ( size_t , uintptr_t ) est analysé comme un déclarateur de nouvelle syntaxe pour une fonction prenant deux paramètres sans nom de type size_t et uintptr_t , et non comme un déclarateur de l'ancienne syntaxe qui débute la définition d'une fonction prenant deux paramètres nommés " size_t " et " uintptr_t ".
- les paramètres peuvent avoir un type incomplet et peuvent utiliser la notation VLA [ * ] (depuis C99) (sauf que dans une définition de fonction , les types des paramètres après conversion tableau-vers-pointeur et fonction-vers-pointeur doivent être complets).
|
Les séquences de spécificateurs d'attributs peuvent également être appliquées aux paramètres de fonction. |
(depuis C23) |
Voir l'opérateur d'appel de fonction pour plus de détails sur la mécanique d'un appel de fonction et return pour le retour depuis les fonctions.
Notes
|
Contrairement au C++, les déclarateurs f ( ) et f ( void ) ont des significations différentes : le déclarateur f ( void ) est un déclarateur de nouveau style (prototype) qui déclare une fonction ne prenant aucun paramètre. Le déclarateur f ( ) est un déclarateur qui déclare une fonction prenant un nombre non spécifié de paramètres (sauf s'il est utilisé dans une définition de fonction) 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 |
(jusqu'en C23) |
Contrairement à une définition de fonction , la liste des paramètres peut être héritée d'un typedef
typedef int p(int q, int r); // p est un type de fonction int(int, int) p f; // déclare int f(int, int)
|
En C89, specifiers-and-qualifiers était optionnel, et s'il était omis, le type de retour de la fonction par défaut était int (éventuellement modifié par le declarator ). *f() { // function returning int* return NULL; } |
(jusqu'à C99) |
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C publiées antérieurement.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| DR 423 | C89 | le type de retour pourrait être qualifié | le type de retour est implicitement déqualifié |
Références
- Norme C23 (ISO/IEC 9899:2024):
-
- 6.7.7.4 Déclarateurs de fonction (incluant les prototypes) (p: 130-132)
- Norme C17 (ISO/CEI 9899:2018) :
-
- 6.7.6.3 Déclarateurs de fonction (incluant les prototypes) (p: 96-98)
- Norme C11 (ISO/CEI 9899:2011) :
-
- 6.7.6.3 Déclarateurs de fonction (incluant les prototypes) (p: 133-136)
- Norme C99 (ISO/CEI 9899:1999) :
-
- 6.7.5.3 Déclarateurs de fonction (incluant les prototypes) (p: 118-121)
- Norme C89/C90 (ISO/IEC 9899:1990) :
-
- 3.5.4.3 Déclarateurs de fonction (incluant les prototypes)
Voir aussi
|
Documentation C++
pour
Déclaration de fonction
|