9. Fonctions à nombre d'arguments variable
Les fonctions usuelles déjà vues ont un nombre
d'arguments fixe et ces arguments sont bien définis par le biais
du prototype. Pourtant, des fonctions de base comme printf()
ou scanf()
ont un nombre d'arguments variable. On va
découvrir comment le C permet de faire cela.
9.1. Prototype d'une fonction à nombre d'arguments variable :
<type de retour> nom_fonction (liste_fixe_de_paramètres, ...);
La fonction a une liste imposée d'arguments fixes, cette liste ne peut être vide (i.e. il y a au moins un argument fixe). Les arguments sont séparés par de virgules. Les trois petits points "..." symbolisent la partie variable du prototype.
Le prototype de la fonction printf()
peut être
ainsi décrit void printf(char * format, ...)
. La
fonction a un paramètre fixe, la chaîne de format (elle
contient les instructions de formatage en %d ...) et des
paramètres variables : les valeurs à afficher.
9.2. Manipulation de la liste d'arguments
On manipule la liste grâce à trois macros et à
un pointeur de liste qui sont définis dans l'entête <stdarg.h>
va_start(liste, nom) |
macro | initialisation du pointeurde liste liste, nom est le nom du dernier paramètre fixe de la fonction. |
va_arg(liste, type) |
macro | récupération de l'argument et déplacement du pointeur sur l'élément suivant. L'élément renvoyé est du type type. |
va_end(liste) |
macro | libération du pointeur de listeliste |
va_list |
pointeur | pointeur de liste |
Remarque 1 :
Pour va_arg, on trouvera
les types int
, double
, char *
... On ne trouvera pas des types comme char
ou float
qui sont implicitement convertis respectivement en int
et
double.
Remarque 2 :
La norme ne fait que conseiller l'utilisation de va_end. A utiliser impérativement donc.
9.3. Exemple :
On va écrire une fonction ouvrable() qui teste si un ensemble de fichiers passé en paramètre est ouvrable dans le mode spécifié :
boolean ouvrable(char * mode, int nombre, ...) {
boolean result = TRUE;
char * fileName;
va_list liste;
va_start(liste, nombre);
while (nombre--) {
/* on peut remplacer par while(fileName)
avec des va_arg bien placés */
fileName = va_arg(liste, char *);
if (!fopen(fileName, mode)) {
result = FALSE;
break;
}
}
va_end(liste);
}
ouvrable("r", 2, "pg1.c", "pg2.c")
teste si les
fichiers pg1.c et pg2.c sont ouvrables en lecture.