Disons que j'ai une fonction C qui prend un nombre variable d'arguments: Comment puis-je appeler une autre fonction qui attend un nombre variable d'arguments de l'intérieur, en passant tous les arguments qui sont entrés dans la première fonction?
Exemple:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
c
variadic-functions
Vicent Marti
la source
la source
Réponses:
Pour transmettre les ellipses, vous devez les convertir en va_list et utiliser cette va_list dans votre deuxième fonction. Plus précisément;
la source
format_string
ne sera guère utile non plus, car il faudrait apporter des modifications in situ à fmt, ce qui ne devrait certainement pas être fait non plus. Les options incluent de se débarrasser complètement de format_string et d'utiliser vfprintf, mais cela fait des hypothèses sur ce que format_string fait réellement, ou que format_string renvoie une chaîne différente. Je vais modifier la réponse pour montrer ce dernier.argptr
et que la fonction appelée utilise duargptr
tout, la seule chose sûre à faire est d'appelerva_end()
puis de redémarrerva_start(argptr, fmt);
pour réinitialiser. Ou vous pouvez l'utiliserva_copy()
si votre système le prend en charge (C99 et C11 l'exigent; C89 / 90 ne l'a pas fait).Il n'y a aucun moyen d'appeler (par exemple) printf sans savoir combien d'arguments vous lui passez, à moins que vous ne vouliez entrer dans des astuces coquines et non portables.
La solution généralement utilisée est de toujours fournir une forme alternative de fonctions vararg, donc
printf
avprintf
qui prend lava_list
place de...
. Les...
versions ne sont que des enveloppes autour desva_list
versions.la source
vsyslog
n'est pas compatible POSIX .Les fonctions variadiques peuvent être dangereuses . Voici une astuce plus sûre:
la source
#define callVardicMethodSafely(values...) ({ values *v = { values }; _actualFunction(values, sizeof(v) / sizeof(*v)); })
En magnifique C ++ 0x, vous pouvez utiliser des modèles variadiques:
la source
Vous pouvez utiliser l'assemblage en ligne pour l'appel de fonction. (dans ce code, je suppose que les arguments sont des caractères).
la source
Vous pouvez également essayer la macro.
la source
Bien que vous puissiez résoudre le passage du formateur en le stockant d'abord dans le tampon local, mais cela nécessite une pile et peut parfois être un problème à traiter. J'ai essayé de suivre et cela semble bien fonctionner.
J'espère que cela t'aides.
la source
La solution de Ross s'est un peu nettoyée. Fonctionne uniquement si tous les arguments sont des pointeurs. L'implémentation du langage doit également prendre en charge la suppression de la virgule précédente si
__VA_ARGS__
est vide (Visual Studio C ++ et GCC le font).la source
Supposons que vous ayez une fonction variadique typique que vous avez écrite. Parce qu'au moins un argument est requis avant le variadic
...
, vous devez toujours écrire un argument supplémentaire lors de l'utilisation.Ou vous?
Si vous encapsulez votre fonction variadique dans une macro, vous n'avez pas besoin d'argument précédent. Considérez cet exemple:
C'est évidemment beaucoup plus pratique, car vous n'avez pas besoin de spécifier l'argument initial à chaque fois.
la source
Je ne sais pas si cela fonctionne pour tous les compilateurs, mais cela a fonctionné jusqu'à présent pour moi.
Vous pouvez ajouter le ... à inner_func () si vous le souhaitez, mais vous n'en avez pas besoin. Cela fonctionne car va_start utilise l'adresse de la variable donnée comme point de départ. Dans ce cas, nous lui donnons une référence à une variable dans func (). Il utilise donc cette adresse et lit les variables après cela sur la pile. La fonction inner_func () lit à partir de l'adresse de pile de func (). Cela ne fonctionne donc que si les deux fonctions utilisent le même segment de pile.
Les macros va_start et va_arg fonctionneront généralement si vous leur donnez un var comme point de départ. Donc, si vous le souhaitez, vous pouvez passer des pointeurs vers d'autres fonctions et les utiliser également. Vous pouvez créer vos propres macros assez facilement. Les macros ne font que taper des adresses mémoire. Cependant, les faire fonctionner pour tous les compilateurs et les conventions d'appel est ennuyeux. Il est donc généralement plus facile d'utiliser ceux fournis avec le compilateur.
la source