Donc, j'ai 2 fonctions qui les deux ont des arguments similaires
void example(int a, int b, ...);
void exampleB(int b, ...);
Maintenant, example
appelle exampleB
, mais comment puis-je transmettre les variables de la liste des arguments de variables sans modifier exampleB
(car cela est déjà utilisé ailleurs aussi).
Vous ne pouvez pas le faire directement; vous devez créer une fonction qui prend un va_list
:
#include <stdarg.h>
static void exampleV(int b, va_list args);
void example(int a, int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
va_end(args);
}
void exampleB(int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
va_end(args);
}
static void exampleV(int b, va_list args)
{
...whatever you planned to have exampleB do...
...except it calls neither va_start nor va_end...
}
Peut-être lancer une pierre dans un étang ici, mais cela semble fonctionner assez bien avec les modèles variadiques C++ 11:
#include <stdio.h>
template<typename... Args> void test(const char * f, Args... args) {
printf(f, args...);
}
int main()
{
int a = 2;
test("%s\n", "test");
test("%s %d %d %p\n", "second test", 2, a, &a);
}
À tout le moins, cela fonctionne avec g++
.
vous devriez créer des versions de ces fonctions qui prennent une liste de va et les transmettre. Regardez vprintf
à titre d'exemple:
int vprintf ( const char * format, va_list arg );
Je voulais aussi emballer printf et j'ai trouvé une réponse utile ici:
Comment passer un nombre variable d'arguments à printf/sprintf
La performance ne m'intéressait pas du tout (je suis sûr que ce morceau de code peut être amélioré de différentes façons, n'hésitez pas à le faire :)), ceci est uniquement destiné au débogage général, c'est pourquoi j'ai:
//Helper function
std::string osprintf(const char *fmt, ...)
{
va_list args;
char buf[1000];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args );
va_end(args);
return buf;
}
que je peux alors utiliser comme ça
Point2d p;
cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";
Les c ++ ostreams sont beaux à certains égards, mais deviennent presque horribles si vous voulez imprimer quelque chose comme ceci avec quelques petites chaînes telles que des parenthèses, des deux points et des virgules insérées entre les chiffres.
Incidemment, de nombreuses implémentations C ont une variante interne de v? Printf, à laquelle IMHO aurait dû faire partie du standard C. Les détails exacts varient, mais une implémentation typique acceptera une structure contenant un pointeur de fonction de sortie de caractère et des informations indiquant ce qui est censé se passer. Cela permet à printf, sprintf et fprintf d’utiliser le même mécanisme "central". Par exemple, vsprintf pourrait être quelque chose comme:
void s_out (PRINTF_INFO * p_inf, char ch) { (* (p_inf-> destptr) ++) = ch; p_inf-> résultat ++; } int vsprintf (char * dest, const char * fmt, va_list args) { PRINTF_INFO p_inf; p_inf.destptr = dest; p_inf.result = 0; p_inf.func = s_out; core_printf (& p_inf, fmt, args); }
La fonction core_printf appelle ensuite p_inf-> func pour chaque caractère à afficher. la fonction de sortie peut ensuite envoyer les caractères à la console, à un fichier, à une chaîne ou à autre chose. Si une implémentation expose la fonction core_printf (et quel que soit le mécanisme d'installation utilisé), vous pouvez l'étendre avec toutes sortes de variations.
Une façon possible est d'utiliser #define:
#define exampleB(int b, ...) example(0, b, __VA_ARGS__)
Sur la base du commentaire que vous enveloppez vsprintf
, et que ceci est étiqueté en C++, je vous suggère de ne pas essayer de le faire, mais de changer votre interface pour utiliser plutôt C++ iostreams. Ils présentent des avantages par rapport à la gamme de fonctions print
, tels que la sécurité des types et la possibilité d’imprimer des éléments que printf
ne serait pas en mesure de gérer. Quelques retouches maintenant pourraient épargner beaucoup de douleur à l’avenir.