Wie kann ich eine Funktion mit Argumenten variabler Länge umschließen?
Lesezeit: 6 Minuten
Prakasch
Ich schaue, um dies in C/C++ zu tun. Ich bin gestoßen Argumente mit variabler Längeaber dies schlägt eine Lösung mit Python und C vor libffi.
Nun, wenn ich das wickeln will printf Funktion mit myprintf.
Ich mache es wie folgt:
void myprintf(char* fmt, ...)
{
va_list args;
va_start(args, fmt);
printf(fmt, args);
va_end(args);
}
int _tmain(int argc, _TCHAR* argv[])
{
int a = 9;
int b = 10;
char v = 'C';
myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n", a, v, b);
return 0;
}
Aber die Ergebnisse sind nicht wie erwartet!
This is a number: 1244780 and
this is a character: h and
another number: 29953463
Was habe ich verpasst?
Die Antwort auf diese Frage lautet sehr anders, jetzt wo C++11 draußen ist.
– Muhende Ente
4. März 2013 um 22:01 Uhr
@MooingDuck Tatsächlich habe ich a hinzugefügt Variadic templates Antwort, glauben Sie, dass es in C++11 einen schöneren Weg gibt?
– Shafik Yaghmour
24. Juli 2013 um 14:47 Uhr
@MooingDuck Eine vararg-Funktion ist keine variadische Vorlagenfunktion. Sie unterscheiden sich in Art und Art.
– rubenvb
24. Juli 2013 um 15:05 Uhr
@rubenvb In diesem Fall denke ich nicht, dass die Unterscheidung wichtig ist, fast alle Referenzen, die ich gesehen habe, preisen sie als direkten Ersatz für die variadische Funktion an: en.cppreference.com/w/cpp/utility/variadic Ich wäre also neugierig, die Unterscheidung zu verstehen, die Sie in diesem Fall sehen.
– Shafik Yaghmour
24. Juli 2013 um 15:17 Uhr
@shafik: Wie wäre es mit dem offensichtlichen Code-Bloat für jede Instanziierung? Wie wäre es mit der Übergabe von Funktionszeigern? Es gibt einige Unterschiede, die Sie beachten müssen. Ich sage nicht, dass Sie es nicht tun sollten, ich sage nur, dass niemand variadische Funktionen abgelehnt hat.
– rubenvb
24. Juli 2013 um 18:14 Uhr
Markieren
Das Problem ist, dass Sie ‘printf’ nicht mit verwenden können va_args. Sie müssen verwenden vprintf wenn Sie variable Argumentlisten verwenden. vprint, vsprintf, vfprintfusw. (es gibt auch “sichere” Versionen in Microsofts C-Laufzeitumgebung, die Pufferüberläufe usw. verhindern.)
Sie probieren Werke wie folgt aus:
void myprintf(char* fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
int _tmain(int argc, _TCHAR* argv[])
{
int a = 9;
int b = 10;
char v = 'C';
myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n", a, v, b);
return 0;
}
Können Sie erklären, warum „Sie nicht verwenden können printf mit va_args” ? Warum vprintf?
– John Strood
29. Oktober 2016 um 17:10 Uhr
@JohnStrood Um dies direkt zu beantworten: Da printf() keine ‘va_list’ als Argument akzeptiert, erwartet es eine variable Anzahl von Argumenten (z. B. “…”), die unterschiedlich ist. Siehe die Manpage für printf() und vprintf(). Nein, wo steht, dass printf() ‘va_list’ als Argument akzeptiert, nur eine variable Anzahl von Argumenten des Typs, den die %-Formatcodes erwarten (int, long, float usw.). Nur die Funktionsfamilie vprintf() akzeptiert eine va_list.
– erko
2. Oktober 2017 um 23:17 Uhr
1 Sie müssen const char verwenden 2 Sie können fmt definitiv nicht als Zeichenfolgenpuffer für vprintf verwenden … haben Sie diesen Code getestet ???
Wie rubenvb betont, sind Kompromisse zu berücksichtigen. Beispielsweise generieren Sie Code für jede Instanz, was zu Code-Bloat führt.
Seien Sie auch gewarnt, dass die Überprüfung des Argumentformats der Funktionsfamilien printf und scanf nicht mit Vorlagen funktioniert. Der Formatstring wird nicht überprüft. Wenn Sie den Format-String falsch erhalten, wird er zur Kompilierzeit nicht abgefangen, kann aber einen Segfault (Absturz) haben oder zur Laufzeit ein unbekanntes Verhalten zeigen.
– Chris Reid
19. Juli 2018 um 23:42 Uhr
Vielen Dank! Ich habe dies mit dem nios2-elf-gcc-Compiler getestet und es funktioniert wie ein Zauber!
– Andak
14. Januar um 14:35 Uhr
David Syke
Ich bin mir auch nicht sicher, was du mit rein meinst.
Sie können der Funktionsdefinition ein Compilerattribut hinzufügen und den Compiler Ihre Formatargumente überprüfen lassen. Klasse Foo { Attribut ((format (printf, 2, 3))) void Write(const char* pMsg, …); }; Foo f; f.Write( “%s %s %d %s” , “Hund” , “Katze”, “Pferd”, “Schwein”); “Warnung: Format gibt den Typ ‘int’ an, aber das Argument hat den Typ ‘const char *’ [-Wformat]”
– Chris Reid
19. Juli 2018 um 23:57 Uhr
Becken
Tatsächlich gibt es eine Möglichkeit, eine Funktion aufzurufen, die kein hat va_list Version aus einem Wrapper. Die Idee ist, Assembler zu verwenden, Argumente auf dem Stapel nicht zu berühren und die Rückgabeadresse der Funktion vorübergehend zu ersetzen.
Ein Beispiel für Visual C x86. call addr_printf Anrufe printf():
Damit das funktioniert, muss die Klasse varargs muss zum Überschreiben implementiert werden operator = das ein Proxy-Objekt zurückgibt, das wiederum überschreibt operator ,. Allerdings ist es meines Wissens nicht möglich, diesen Variantentyp in aktuellem C++ sicher zu machen, da es durch Typlöschung funktionieren müsste.
C++03 verwenden könnte boost::tuple die Möglichkeiten hat, die oben genannten Dinge sicher zu tun.
– Muhende Ente
4. März 2013 um 22:03 Uhr
Peter Mortensen
Wie meinen Sie eine reine C/C++-Lösung?
Der rest-Parameter (…) wird in der C-Laufzeit plattformübergreifend unterstützt.
C++03 verwenden könnte boost::tuple die Möglichkeiten hat, die oben genannten Dinge sicher zu tun.
– Muhende Ente
4. März 2013 um 22:03 Uhr
Peter Mortensen
void myprintf(char* fmt, ...)
{
va_ list args;
va_ start(args, fmt);
printf(fmt, args); // This is the fault. "vprintf(fmt, args);"
// should have been used.
va_ end(args);
}
Wenn Sie nur versuchen anzurufen DruckfDa ist ein Druckf Variante genannt vprintf das nimmt die va_liste direkt: vprintf(fmt, args);
14096100cookie-checkWie kann ich eine Funktion mit Argumenten variabler Länge umschließen?yes
Die Antwort auf diese Frage lautet sehr anders, jetzt wo C++11 draußen ist.
– Muhende Ente
4. März 2013 um 22:01 Uhr
@MooingDuck Tatsächlich habe ich a hinzugefügt
Variadic templates
Antwort, glauben Sie, dass es in C++11 einen schöneren Weg gibt?– Shafik Yaghmour
24. Juli 2013 um 14:47 Uhr
@MooingDuck Eine vararg-Funktion ist keine variadische Vorlagenfunktion. Sie unterscheiden sich in Art und Art.
– rubenvb
24. Juli 2013 um 15:05 Uhr
@rubenvb In diesem Fall denke ich nicht, dass die Unterscheidung wichtig ist, fast alle Referenzen, die ich gesehen habe, preisen sie als direkten Ersatz für die variadische Funktion an: en.cppreference.com/w/cpp/utility/variadic Ich wäre also neugierig, die Unterscheidung zu verstehen, die Sie in diesem Fall sehen.
– Shafik Yaghmour
24. Juli 2013 um 15:17 Uhr
@shafik: Wie wäre es mit dem offensichtlichen Code-Bloat für jede Instanziierung? Wie wäre es mit der Übergabe von Funktionszeigern? Es gibt einige Unterschiede, die Sie beachten müssen. Ich sage nicht, dass Sie es nicht tun sollten, ich sage nur, dass niemand variadische Funktionen abgelehnt hat.
– rubenvb
24. Juli 2013 um 18:14 Uhr