Déclarations et prototypes
Remonter à Fonctions - Index
Dans le style de déclaration défini à l'origine par Kernighan et Ritchie, une fonction pouvait implicitement être déclarée par son apparition dans un appel de fonction, ou explicitement de la façon suivante :
<type> func();
où type est le type de la valeur renvoyée par la fonction (par défaut, int).
<type> func(liste-déclarateurs-paramètre);
Il est possible de déclarer une fonction renvoyant n'importe quel type, sauf tableau ou fonction. Cette approche ne permet pas au compilateur de vérifier que le type ou le nombre d'arguments utilisés dans un appel de fonction concorde avec la déclaration.
Ce problème a été résolu par l'introduction des prototypes de fonctions dont la syntaxe de déclaration est la suivante :
extern long lmax(long v1, long v2); /* prototype */ foo() { int limit = 32; char ch = 'A'; long mval; mval = lmax(limit,ch); /* appel de la fonction */ }
Remarque : Vous pouvez activer un avertissement dans le compilateur en ligne de commande : "Function called without a prototype.".
Les déclarateurs spécifient le type de chaque paramètre de la fonction. Le compilateur utilise ces informations pour vérifier la validité des appels. Il peut aussi attribuer aux arguments le type adéquat. Supposons que vous ayez le fragment de code suivant :
char *strcpy(char *dest, const char *source);
Ce programme, du fait qu'il contient un prototype de fonction pour lmax
, convertit limit
et ch
à long, en appliquant les règles standard d'affectation, avant de les placer sur la pile pour l'appel de lmax
. Sans le prototype, limit
et ch
seraient placés sur la pile en tant qu'entier et caractère ; dans ce cas, la pile passée à lmax
n'aurait pas la taille ni le contenu que lmax
attendait, causant ainsi certains problèmes. Le style de déclaration classique ne permettant pas de vérifier ni le type ni le nombre des paramètres des fonctions, l'utilisation des prototypes facilite considérablement la détection des erreurs de programmation.
Les prototypes de fonctions sont également utiles pour documenter le code. Par exemple, la fonction strcpy
accepte deux paramètres : une chaîne source et une chaîne destinataire. La question est de les différencier. Le prototype de fonction :
func(void);
rend claire la formulation. Si un fichier en-tête contient des prototypes de fonctions, vous pouvez l'imprimer pour savoir comment écrire les programmes qui appellent ces fonctions. Si vous introduisez un identificateur dans un paramètre de prototype, il n'est utilisé que pour d'éventuels messages d'erreur relatifs à ce paramètre.
Un déclarateur de fonction avec le mot void entre parenthèses indique une fonction qui n'accepte aucun argument :
f(int *count, long total, ...);
En C++, func()
déclare aussi une fonction sans argument.
Un prototype de fonction déclare généralement une fonction acceptant un nombre fixe de paramètres. Pour les fonctions qui admettent un nombre variable de paramètres (comme printf
), un prototype peut se terminer par des points de suspension (...), comme suit :
int f(); /* En C, une fonction renvoyant un int sans information concernant ses paramètres. C'est le "style traditionnel" de K&R */ int f(); /* En C++, une fonction sans argument */ int f(void); /* Une fonction sans paramètre renvoyant un int. */ int p(int,long); /* Une fonction renvoyant un int et acceptant deux paramètres : - le premier, un int; - le second, un long. */ int __pascal q(void); /* Une fonction pascal renvoyant un int, sans paramètre. */ int printf(char *format,...); /* Une fonction renvoyant un int et acceptant un pointeur sur un paramètre fixe char et un certain nombre d'autres paramètres de type inconnu. */ int (*fp)(int); /* Un pointeur sur une fonction renvoyant un int et acceptant un seul paramètre int. */
Avec cette forme de prototype, les paramètres fixes sont vérifiés au moment de la compilation, et les paramètres variables sont transmis sans contrôle de type.
Remarque : Les fichiers stdarg.h et varargs.h contiennent des macros que vous pouvez utiliser dans des fonctions définies par vous, avec un nombre variable de paramètres.
Voici quelques exemples de déclarateurs de fonctions et de prototypes :
int f(); /* In C, a function returning an int with no information about parameters. This is the K&R "classic style" */ int f(); /* In C++, a function taking no arguments */ int f(void); /* A function returning an int that takes no parameters. */ int p(int,long); /* A function returning an int that accepts two parameters: - the first, an int; - the second, a long. */ int __pascal q(void); /* A pascal function returning an int that takes no parameters at all. */ int printf(char *format,...); /*A function returning an int and accepting a pointer to a char fixed parameter and any number of additional parameters of unknown type. */ int (*fp)(int); /* A pointer to a function returning an int and requiring an int parameter. */