web-dev-qa-db-fra.com

Passer des arguments variables à une autre fonction qui accepte une liste d'arguments variables

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).

92
Not Available

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...
}
107
Jonathan Leffler

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++.

23
Vincent Fourmond

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 );
15
tenfour

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.

4
Axel

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.

2
supercat

Une façon possible est d'utiliser #define:

#define exampleB(int b, ...)  example(0, b, __VA_ARGS__)
0
Shai

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.

0
Mark B