Passer un nombre variable d'argument
Le langage C a une possibilité très utile pour la définition de fonctions: le passage d'argument en nombre variable. Cette fonctionnalité est utilisée sans arrêt avec printf, mais savez-vous comment l'utiliser pour vos propre fonctions?
Une fonctionnalité bien pratique du C est la possibilité d'avoir un nombre d'argument variable pour les fonctions.
Cette fonctionnalité, on l'utilise tout le temps avec printf et les autres fonctions de formatage. Par contre, la façon de mettre en œuvre ces merveilleuses fonctions est souvent inconnue. Essayons de remédier à cela au plus vite.
Signature de la fonction
Une fonction à argument variable (appelée aussi fonction variadique), doit avoir au moins un argument obligatoire. Les arguments obligatoires doivent toujours être placés avant les arguments facultatifs.
Pour spécifier les arguments facultatif, il faut utiliser la notation avec un ellipsis (trois petit points: "...").
Voici le prototype de printf et d'une telle fonction qui n'a que des arguments facultatifs:
int printf (const char *format, ...); void mean(int first, ...);
Récupérer les arguments
Voici la partie difficile, comment récupérer les arguments. Il n'y a pas de syntaxe spéciale du langage C, il suffit d'utiliser les macros fournies par la bibliothèques <stdarg.h>.
Il y a trois macros a retenir:
- void va_start (va_list ap, last): initialise la liste d'argument
- type va_arg (va_list ap, type): retourne la variable suivate du type donné
- void va_end (va_list ap): nettoie la mémoire allouée par var_start
Il faut aussi connaître le type va_list, qui est une structure interne à stdarg pour manipuler les arguments en nombre variable.
Un exemple
Voici un exemple plutôt qu'un long discourt:
#include <stdio.h>
#include <stdarg.h>
int mean (int number, ...)
{
va_list ap;
int n=number, sum=0;
va_start (ap, number);
for(;n>0;n--){
sum += va_arg (ap, int);
}
va_end(ap);
return sum/number;
}
int main(){
int d = mean(4, 1, 1, 5, 5);
printf("%d\n", d);
return 0;
}
Détaillons les parties qui valent le coup.
Premièrement, il y a "va_list ap" qui est une structure indispensable pour manipuler les arguments en nombre variable.
Ensuite, il faut utiliser va_start, qui permet d'initialiser la va_list. Le premier argument de va_start est la va_list qu'il faut initialiser. Le second argument est le dernier argument obligatoire de la fonction.
Le corps du système est va_arg, qui permet de récupérer les arguments en nombre variable. Chaque appel à cette méthode renvoie un élément de la liste, et incrémente un pointeur interne. Cette mécanique fait que chaque appel à va_list fournit l'argument suivant dans la liste d'arguments.
Le type de retour d'un appel à va_list est le type passé comme second argument. Cela veut dire qu'il faut un moyen externe pour déterminer les types des arguments, le cas le plus courant est une chaîne de caractère comme pour printf.
Finalement, et il ne faut pas l'oublier sous peine de fuite de mémoire, il faut appeler va_end. Cette macro (ou fonction selon l'implémentation) nettoie la mémoire allouée par va_start.
Vérification de type
Attention à ce qui suit pour la sécurité. Vous ne pouvez pas connaître le nombre d'argument qui ont vraiment été passée à une fonction variadique.
Donc vous pouvez:
- Passer trop d'argument
- Appeler va_arg plus souvent qu'il n'y a d'arguments
Le premier cas n'est pas trop grave, vous oubliez des arguments. Le second l'est plus, car vous accédez à la partie basse de la pile.
Pour éviter les problèmes, deux solutions à toujours mettre en place:
- la façon dont vous passez le nombre et les types d'arguments doit être sûre
- documentez correctement, commentaire et documentation obligatoire et bien visible

