Prototypes de fonction

Une déclaration de fonction précède la définition de la fonction et spécifie le nom, le type de retour, la classe de stockage et d’autres attributs d’une fonction. Pour être un prototype, la déclaration de fonction doit également établir des types et des identificateurs pour les arguments de la fonction.

Syntaxe

declaration :
declaration-specifiers attribute-seq opterinit-declarator-listopter;

/* attribute-seq opt est spécifique à Microsoft */

declaration-specifiers :
storage-class-specifier declaration-specifiers opter
type-specifier declaration-specifiers opter
type-qualifier declaration-specifiers opter

init-declarator-list :
init-declarator
init-declarator-list , init-declarator

init-declarator :
declarator
declarator = initializer

declarator :
pointer optezdirect-declarator

direct-declarator: /* Un déclarateur de fonction */
direct-declarator ( parameter-type-list ) /* Déclarateur de nouveau style */
direct-declarator ( identifier-list opter) /* Déclarateur de style obsolète */

Le prototype a la même forme que la définition de fonction, sauf qu’il est arrêté par un point-virgule immédiatement après la parenthèse fermante et n’a donc aucun corps. Dans les deux cas, le type de retour doit accepter le type de retour spécifié dans la définition de fonction.

Les prototypes de fonction ont les utilisations importantes suivantes :

  • Ils établissent le type de retour pour les fonctions qui retournent des types autres que int. Bien que les fonctions qui retournent int des valeurs ne nécessitent pas de prototypes, les prototypes sont recommandés.

  • Sans prototypes complets, les conversions standard sont effectuées, mais aucune tentative n’est effectuée pour vérifier le type ou le nombre d’arguments avec le nombre de paramètres.

  • Les prototypes sont utilisés pour initialiser des pointeurs vers des fonctions avant que ces fonctions ne soient définies.

  • La liste des paramètres est utilisée pour vérifier que les arguments de l’appel de fonction correspondent aux paramètres de la définition de fonction.

Le type converti de chaque paramètre détermine l’interprétation des arguments que l’appel de fonction place sur la pile. Une incompatibilité de type entre un argument et un paramètre peut entraîner l’interprétation incorrecte des arguments sur la pile. Par exemple, sur un ordinateur 16 bits, si un pointeur 16 bits est passé en tant qu’argument, puis déclaré en tant que long paramètre, les 32 premiers bits de la pile sont interprétés comme un long paramètre. Cette erreur crée des problèmes non seulement avec le long paramètre, mais avec tous les paramètres suivants. Vous pouvez détecter les erreurs de ce type en déclarant des prototypes de fonction complets pour toutes les fonctions.

Un prototype établit les attributs d’une fonction. Ensuite, les appels de fonction qui précèdent la définition de la fonction (ou qui se produisent dans d’autres fichiers sources) peuvent être vérifiés pour les incompatibilités de type argument et de retour. Par exemple, si vous spécifiez le static spécificateur de classe de stockage dans un prototype, vous devez également spécifier la static classe de stockage dans la définition de fonction.

Les déclarations de paramètre complètes (int a) peuvent être mélangées à des déclarateurs abstraits (int) dans la même déclaration. Par exemple, la déclaration suivante est légale :

int add( int a, int );

Le prototype peut inclure à la fois le type et un identificateur pour chaque expression passée en tant qu’argument. Toutefois, ces identificateurs sont uniquement dans l’étendue jusqu’à la fin de la déclaration. Le prototype peut également refléter le fait que le nombre d’arguments est variable ou qu’aucun argument n’est passé. Sans cette liste, les incompatibilités peuvent ne pas être révélées, de sorte que le compilateur ne peut pas générer de messages de diagnostic concernant ces derniers. Pour plus d’informations sur la vérification de type, consultez Arguments.

L’étendue du prototype dans le compilateur Microsoft C est désormais conforme à ANSI lors de la compilation avec l’option du /Za compilateur. Si vous déclarez une ou une structunion balise dans un prototype, la balise est entrée à cette étendue plutôt qu’à l’étendue globale. Par exemple, lors de la compilation avec /Za pour la conformité ANSI, vous ne pouvez jamais appeler cette fonction sans obtenir une erreur d’incompatibilité de type :

void func1( struct S * );

Pour corriger votre code, définissez ou déclarez l’étendue globale ou union à l’échelle struct globale avant le prototype de fonction :

struct S;
void func1( struct S * );

Sous /Ze, la balise est toujours entrée dans l’étendue globale.

Voir aussi

Fonctions