363 Stimmen

Übergabe einer variablen Anzahl von Argumenten

Angenommen, ich habe eine C-Funktion, die eine variable Anzahl von Argumenten annimmt: Wie kann ich eine andere Funktion aufrufen, die eine variable Anzahl von Argumenten erwartet, und dabei alle Argumente übergeben, 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);
 }

9voto

Jagdish Punkte 1722

Sie können auch Makro 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;
}

7voto

Yoda Punkte 121

Sie können Inline-Assembly für den Funktionsaufruf verwenden. (In diesem Code nehme ich an, 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);
    }

2voto

BSalita Punkte 7515

Die Lösung von Ross wurde ein wenig bereinigt. Funktioniert nur, wenn alle Args Zeiger sind. Außerdem muss die Sprachimplementierung das Elidieren des vorherigen Kommas unterstützen, wenn __VA_ARGS__ leer ist (sowohl Visual Studio C++ als auch 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);}

2voto

Ali80 Punkte 2331

Kurze Antwort

/// logs all messages below this level, level 0 turns off LOG 
#ifndef LOG_LEVEL
#define LOG_LEVEL 5  // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
#endif
#define _LOG_FORMAT_SHORT(letter, format) "[" #letter "]: " format "\n"

/// short log
#define log_s(level, format, ...)     \                                                                                  
    if (level <= LOG_LEVEL)            \                                                                                     
    printf(_LOG_FORMAT_SHORT(level, format), ##__VA_ARGS__)

Verwendung

log_s(1, "fatal error occurred");
log_s(3, "x=%d and name=%s",2, "ali");

Ausgabe

[1]: fatal error occurred
[3]: x=2 and name=ali

Protokoll mit Datei- und Zeilennummer

const char* _getFileName(const char* path)
{
    size_t i = 0;
    size_t pos = 0;
    char* p = (char*)path;
    while (*p) {
        i++;
        if (*p == '/' || *p == '\\') {
            pos = i;
        }
        p++;
    }
    return path + pos;
}

#define _LOG_FORMAT(letter, format)      \                                                                        
    "[" #letter "][%s:%u] %s(): " format "\n", _getFileName(__FILE__), __LINE__, __FUNCTION__

#ifndef LOG_LEVEL
#define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
#endif

/// long log
#define log_l(level, format, ...)     \                                                                               
    if (level <= LOG_LEVEL)            \                                                                                         
    printf(_LOG_FORMAT(level, format), ##__VA_ARGS__)

Verwendung

log_s(1, "fatal error occurred");
log_s(3, "x=%d and name=%s",2, "ali");

Ausgabe

[1][test.cpp:97] main(): fatal error occurred
[3][test.cpp:98] main(): x=2 and name=ali

benutzerdefinierte Druckfunktion

können Sie eine eigene Druckfunktion schreiben und die ... args und es ist auch möglich, dies mit den oben genannten Methoden zu kombinieren. source from aquí

int print_custom(const char* format, ...)
{
    static char loc_buf[64];
    char* temp = loc_buf;
    int len;
    va_list arg;
    va_list copy;
    va_start(arg, format);
    va_copy(copy, arg);
    len = vsnprintf(NULL, 0, format, arg);
    va_end(copy);
    if (len >= sizeof(loc_buf)) {
        temp = (char*)malloc(len + 1);
        if (temp == NULL) {
            return 0;
        }
    }
    vsnprintf(temp, len + 1, format, arg);
    printf(temp); // replace with any print function you want
    va_end(arg);
    if (len >= sizeof(loc_buf)) {
        free(temp);
    }
    return len;
}

0voto

Engineer Punkte 7950

Nehmen wir an, Sie haben eine typische variadische Funktion, die Sie geschrieben haben. Da mindestens ein Argument vor dem variadischen Argument erforderlich ist ... müssen Sie bei der Verwendung immer ein zusätzliches Argument angeben.

Oder willst du das?

Wenn Sie Ihre variadische Funktion in ein Makro verpacken, brauchen Sie kein vorangehendes Argument. Betrachten Sie dieses Beispiel:

#define LOGI(...)
    ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))

Dies ist natürlich viel bequemer, da Sie nicht jedes Mal das Anfangsargument angeben müssen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X