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.

Valid XHTML 1.0!