it-swarm.com.de

Variable Anzahl von Argumenten übergeben

Angenommen, ich habe eine C-Funktion, die eine variable Anzahl von Argumenten akzeptiert: Wie kann ich eine andere Funktion aufrufen, die eine variable Anzahl von Argumenten erwartet und alle Argumente übergibt, die in die erste Funktion eingegangen sind?

Beispiel:

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);
 }
324
Vicent Marti

Um die Ellipsen weiterzugeben, müssen Sie sie in eine va_list konvertieren und diese va_list in Ihrer zweiten Funktion verwenden. Speziell;

void format_string(char *fmt,va_list argptr, char *formatted_string);


void debug_print(int dbg_lvl, char *fmt, ...) 
{    
 char formatted_string[MAX_FMT_SIZE];

 va_list argptr;
 va_start(argptr,fmt);
 format_string(fmt, argptr, formatted_string);
 va_end(argptr);
 fprintf(stdout, "%s",formatted_string);
}
206
SmacL

Es gibt keine Möglichkeit, printf aufzurufen, ohne zu wissen, wie viele Argumente Sie an printf übergeben, es sei denn, Sie möchten sich auf freche und nicht tragbare Tricks einlassen.

Die allgemein verwendete Lösung besteht darin, immer eine alternative Form von vararg-Funktionen bereitzustellen, sodass printfvprintf hat, das ein va_list anstelle des .... Das ... Versionen sind nur Wrapper um den va_list Versionen.

57
Mike F

Variadic Functions kann gefährlich sein. Hier ist ein sicherer Trick:

   void func(type* values) {
        while(*values) {
            x = *values++;
            /* do whatever with x */
        }
    }

func((type[]){val1,val2,val3,val4,0});
51
Rose Perrone

In großartigem C++ 0x könnten Sie verschiedene Vorlagen verwenden:

template <typename ... Ts>
void format_string(char *fmt, Ts ... ts) {}

template <typename ... Ts>
void debug_print(int dbg_lvl, char *fmt, Ts ... ts)
{
  format_string(fmt, ts...);
}
28
user2023370

Sie können die Inline-Assembly für den Funktionsaufruf verwenden. (In diesem Code gehe ich davon aus, dass die Argumente Zeichen sind).

void format_string(char *fmt, ...);
void debug_print(int dbg_level, int numOfArgs, char *fmt, ...)
    {
        va_list argumentsToPass;
        va_start(argumentsToPass, fmt);
        char *list = new char[numOfArgs];
        for(int n = 0; n < numOfArgs; n++)
            list[n] = va_arg(argumentsToPass, char);
        va_end(argumentsToPass);
        for(int n = numOfArgs - 1; n >= 0; n--)
        {
            char next;
            next = list[n];
            __asm Push next;
        }
        __asm Push fmt;
        __asm call format_string;
        fprintf(stdout, fmt);
    }
7
Yoda

Sie können Makro auch versuchen.

#define NONE    0x00
#define DBG     0x1F
#define INFO    0x0F
#define ERR     0x07
#define EMR     0x03
#define CRIT    0x01

#define DEBUG_LEVEL ERR

#define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: "
#define WHEREARG __FILE__,__func__,__LINE__
#define DEBUG(...)  fprintf(stderr, __VA_ARGS__)
#define DEBUG_PRINT(X, _fmt, ...)  if((DEBUG_LEVEL & X) == X) \
                                      DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__)

int main()
{
    int x=10;
    DEBUG_PRINT(DBG, "i am x %d\n", x);
    return 0;
}
6
GeekyJ

Sie können das Übergeben des Formatierers zwar lösen, indem Sie ihn zuerst im lokalen Puffer speichern. Dies muss jedoch gestapelt werden und kann zu Problemen führen. Ich habe versucht zu folgen und es scheint gut zu funktionieren.

#include <stdarg.h>
#include <stdio.h>

void print(char const* fmt, ...)
{
    va_list arg;
    va_start(arg, fmt);
    vprintf(fmt, arg);
    va_end(arg);
}

void printFormatted(char const* fmt, va_list arg)
{
    vprintf(fmt, arg);
}

void showLog(int mdl, char const* type, ...)
{
    print("\nMDL: %d, TYPE: %s", mdl, type);

    va_list arg;
    va_start(arg, type);
    char const* fmt = va_arg(arg, char const*);
    printFormatted(fmt, arg);
    va_end(arg);
}

int main() 
{
    int x = 3, y = 6;
    showLog(1, "INF, ", "Value = %d, %d Looks Good! %s", x, y, "Infact Awesome!!");
    showLog(1, "ERR");
}

Hoffe das hilft.

5
VarunG

Ross 'Lösung hat ein bisschen aufgeräumt. Funktioniert nur, wenn alle Argumente Zeiger sind. Die Implementierung der Sprache muss auch das Entfernen des vorherigen Kommas unterstützen, wenn __VA_ARGS__ ist leer (Visual Studio C++ und GCC tun dies).

// pass number of arguments version
 #define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__}; _actualFunction(args+1,sizeof(args) / sizeof(*args) - 1);}


// NULL terminated array version
 #define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__, NULL}; _actualFunction(args+1);}
1
BSalita