Namespaces
Variants

Function declarations

From cppreference.net

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)

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
1) Déclaration de fonction de style moderne (C89). Cette déclaration introduit à la fois le désignateur de fonction lui-même et sert également de prototype de fonction pour toute future expression d'appel de fonction , forçant les conversions des expressions d'arguments vers les types de paramètres déclarés et les vérifications à la compilation du nombre d'arguments.
int max(int a, int b); // declaration
int n = max(12.01, 3.14); // OK, conversion from double to int
2) (jusqu'à C23) Définition de fonction de style ancien (K&R). Cette déclaration n'introduit pas de prototype et toute future expression d'appel de fonction effectuera des promotions d'arguments par défaut et invoquera un comportement indéfini si le nombre d'arguments ne correspond pas au nombre de paramètres.
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) Déclaration de fonction non prototype. Cette déclaration n'introduit pas de prototype (jusqu'au C23) . Une nouvelle déclaration de fonction équivalente à parameter-list void (depuis C23) .

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