Übergeben einer variablen Anzahl von Argumenten

Lesezeit: 6 Minuten

Benutzeravatar von Vicent Marti
Vicent Martin

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 von innen erwartet, und alle Argumente übergeben, die in die erste Funktion gelangt 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);
 }

  • Ihr Beispiel sieht für mich etwas seltsam aus, da Sie fmt sowohl an format_string() als auch an fprintf() übergeben. Sollte format_string() irgendwie einen neuen String zurückgeben?

    – Christoph Johnson

    15. Oktober 2008 um 17:14 Uhr

  • Beispiel macht keinen Sinn. Es war nur, um den Umriss des Codes zu zeigen.

    – Vicent Martí

    15. Oktober 2008 um 17:22 Uhr

  • “sollte gegoogelt werden”: Ich stimme nicht zu. Google hat viel Lärm (unklare, oft verwirrende Informationen). Eine gute (abgestimmte, akzeptierte Antwort) auf Stackoverflow zu haben, hilft wirklich!

    – Ansgar

    6. Februar 2009 um 9:53 Uhr

  • Nur zum Abwägen: Ich bin von Google auf diese Frage gekommen, und da es sich um einen Stapelüberlauf handelte, war ich sehr zuversichtlich, dass die Antwort nützlich sein würde. Also frag weg!

    – Tenpn

    24. Februar 2009 um 12:18 Uhr

  • @Ilya: Wenn niemand etwas außerhalb von Google aufgeschrieben hätte, gäbe es keine Informationen, nach denen man bei Google suchen könnte.

    – Erik Kaplun

    29. August 2012 um 20:27 Uhr


Benutzeravatar von SmacL
SmacL

Um die Ellipsen weiterzugeben, initialisieren Sie a va_list wie gewohnt und übergeben Sie es einfach an Ihre zweite Funktion. Sie verwenden nicht va_arg(). 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);
}

  • Der Code stammt aus der Frage und ist eigentlich nur eine Veranschaulichung, wie Ellipsen konvertiert werden, und nicht irgendetwas Funktionelles. Wenn man es sich ansieht format_string wird auch kaum nützlich sein, da es in situ Änderungen an fmt vornehmen müsste, was sicherlich auch nicht getan werden sollte. Zu den Optionen würde gehören, format_string ganz loszuwerden und vfprintf zu verwenden, aber das macht Annahmen darüber, was format_string tatsächlich tut, oder format_string soll einen anderen String zurückgeben. Ich werde die Antwort bearbeiten, um letzteres zu zeigen.

    – SmacL

    24. Februar 2012 um 16:35 Uhr

  • Wenn Ihre Formatzeichenfolge dieselben Formatzeichenfolgenbefehle wie printf verwendet, können Sie auch einige Compiler wie gcc und clang dazu bringen, Ihnen Warnungen auszugeben, wenn Ihre Formatzeichenfolge nicht mit den tatsächlich übergebenen Argumenten kompatibel ist. Siehe das GCC-Funktionsattribut ‘ Format’ für weitere Details: gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html.

    – Doug Richardson

    16. November 2013 um 19:00 Uhr


  • Dies scheint nicht zu funktionieren, wenn Sie die Argumente zweimal hintereinander übergeben.

    – Fotanus

    10. Juni 2015 um 4:20 Uhr


  • @fotanus: wenn du eine funktion aufrufst mit der argptr und die aufgerufene Funktion verwendet die argptr Überhaupt ist das einzig Sichere, anzurufen va_end() und dann neu starten va_start(argptr, fmt); neu zu initialisieren. Oder Sie können verwenden va_copy() wenn Ihr System es unterstützt (C99 und C11 erfordern es; C89/90 nicht).

    – Jonathan Leffler

    15. Juni 2015 um 1:32 Uhr

  • Bitte beachten Sie, dass der Kommentar von @ThomasPadron-McCarthy jetzt veraltet ist und der endgültige fprintf in Ordnung ist.

    – Friedrich

    13. September 2016 um 20:19 Uhr

Es gibt keine Möglichkeit, (z. B.) printf aufzurufen, ohne zu wissen, wie viele Argumente Sie ihm übergeben, es sei denn, Sie möchten in ungezogene und nicht tragbare Tricks geraten.

Die allgemein verwendete Lösung besteht darin, immer eine alternative Form von vararg-Funktionen bereitzustellen, also printf hat vprintf was dauert va_list anstelle der .... Das ... Versionen sind nur Wrapper um die va_list Versionen.

  • Beachten Sie, dass vsyslog ist nicht Posix konform.

    – patryk.beza

    9. August 2016 um 12:29 Uhr

Benutzeravatar von Rose Perrone
Rose Perrone

Variadische Funktionen kann sein gefährlich. Hier ist ein sicherer Trick:

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

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

  • Noch besser ist dieser Trick: #define callVardicMethodSafely(values...) ({ values *v = { values }; _actualFunction(values, sizeof(v) / sizeof(*v)); })

    – Richard J.Ross III

    3. März 2012 um 22:54 Uhr

  • @RichardJ.RossIII Ich wünschte, Sie würden Ihren Kommentar erweitern, er ist so kaum lesbar, ich kann die Idee hinter dem Code nicht erkennen und er sieht tatsächlich sehr interessant und nützlich aus.

    – Penelope

    30. März 2012 um 10:09 Uhr

  • @ArtOfWarfare Ich bin mir nicht sicher, ob ich zustimme, dass es ein schlechter Hack ist, Rose hat eine großartige Lösung, aber es beinhaltet die Eingabe von func( (type[]){Wert1, Wert2, 0}); was sich klobig anfühlt, während wenn Sie #define func_short_cut(…) func((type[]){VA_ARGS}); dann könnten Sie einfach func_short_cut(1, 2, 3, 4, 0) aufrufen; was Ihnen die gleiche Syntax wie eine normale variadische Funktion mit dem zusätzlichen Vorteil von Roses nettem Trick gibt … was ist hier das Problem?

    – Chrispepper1989

    24. Juli 2013 um 14:05 Uhr


  • Was ist, wenn Sie 0 als Argument übergeben möchten?

    – Julian Gold

    10. September 2014 um 8:50 Uhr

  • Dazu müssen Ihre Benutzer daran denken, mit einer abschließenden 0 anzurufen. Wie ist es sicherer?

    – vgl. engr

    26. Februar 2016 um 21:26 Uhr

Benutzeravatar von user2023370
Benutzer2023370

In großartigem C ++ 11 können 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...);
}

Benutzeravatar von VarunG
VarunG

Sie können zwar das Übergeben des Formatierers lösen, indem Sie ihn zuerst im lokalen Puffer speichern, aber das erfordert Stack und kann manchmal ein Problem darstellen. Ich habe folgendes versucht 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.

Benutzeravatar von Yoda
Yoda

Sie können die Inline-Assemblierung 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);
    }

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;
}

1427460cookie-checkÜbergeben einer variablen Anzahl von Argumenten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy