So erstellen Sie ein variadisches Makro (variable Anzahl von Argumenten)
Lesezeit: 7 Minuten
Hasen
Ich möchte ein Makro in C schreiben, das eine beliebige Anzahl von Parametern akzeptiert, keine bestimmte Anzahl
Beispiel:
#define macro( X ) something_complicated( whatever( X ) )
wo X ist eine beliebige Anzahl von Parametern
Ich brauche das weil whatever ist überladen und kann mit 2 oder 4 Parametern aufgerufen werden.
Ich habe zweimal versucht, das Makro zu definieren, aber die zweite Definition hat die erste überschrieben!
Der Compiler, mit dem ich arbeite, ist g++ (genauer gesagt mingw)
Möchten Sie C oder C++? Wenn Sie C verwenden, warum kompilieren Sie mit einem C++-Compiler? Um richtige variadische C99-Makros zu verwenden, sollten Sie mit einem C-Compiler kompilieren, der C99 unterstützt (wie gcc), nicht mit einem C++-Compiler, da C++ keine standardmäßigen variadischen Makros hat.
– Chris Lutz
25. März 2009 um 2:13 Uhr
Nun, ich nahm an, dass C++ in dieser Hinsicht eine Supermenge von C ist.
Für zukünftige Leser: C ist nicht eine Untergruppe von C++. Sie haben viele, viele Dinge gemeinsam, aber es gibt Regeln, die verhindern, dass sie Teilmenge und Obermenge voneinander sind.
– Pharap
9. September 2017 um 0:28 Uhr
C99-Weg, auch vom VC++-Compiler unterstützt.
#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)
Ich glaube nicht, dass C99 das ## vorher benötigt VA_ARGS. Das könnte nur VC++ sein.
– Chris Lutz
25. März 2009 um 2:18 Uhr
Der Grund für ## vor VA_ARGS ist, dass es das vorangestellte Komma verschluckt, falls die Variablenargumentliste leer ist, z. FOO(“a”) wird zu printf(“a”) erweitert. Dies ist eine Erweiterung von gcc (und vielleicht vc++), C99 erfordert, dass mindestens ein Argument anstelle der Auslassungspunkte vorhanden ist.
– jpalecek
26. März 2009 um 20:20 Uhr
## wird nicht benötigt und ist nicht tragbar. #define FOO(...) printf(__VA_ARGS__) erledigt die Arbeit auf tragbare Weise; das fmt Parameter kann aus der Definition weggelassen werden.
– alecov
11. Juni 2012 um 20:14 Uhr
IIRC, das ## ist GCC-spezifisch und erlaubt die Übergabe von Nullparametern
– Mawg sagt, Monica wieder einzusetzen
23. Juli 2012 um 4:28 Uhr
Die ##-Syntax funktioniert auch mit llvm/clang und dem Visual Studio Compiler. Es ist also möglicherweise nicht portabel, wird aber von den wichtigsten Compilern unterstützt.
– K. Biermann
17. Dezember 2014 um 21:13 Uhr
cmccabe
__VA_ARGS__ ist der Standardweg, es zu tun. Verwenden Sie keine Compiler-spezifischen Hacks, wenn Sie nicht müssen.
Ich ärgere mich sehr, dass ich den ursprünglichen Beitrag nicht kommentieren kann. Auf jeden Fall ist C++ keine Obermenge von C. Es ist wirklich dumm, Ihren C-Code mit einem C++-Compiler zu kompilieren. Tu nicht, was Donny nicht tut.
“Es ist wirklich albern, seinen C-Code mit einem C++-Compiler zu kompilieren” => Wird nicht von allen (einschließlich mir) so angesehen. Siehe zum Beispiel C++ Core Guidelines: CPL.1: Bevorzugen Sie C++ gegenüber C , CPL.2: Wenn Sie C verwenden müssen, verwenden Sie die gemeinsame Teilmenge von C und C++ und kompilieren Sie den C-Code als C++. Es fällt mir schwer, mir vorzustellen, welche “Nur-C-Ismen” man wirklich braucht, damit es sich lohnt, nicht in der kompatiblen Teilmenge zu programmieren, und die C- und C++-Komitees haben hart daran gearbeitet, diese kompatible Teilmenge verfügbar zu machen.
– HostileFork sagt, vertraue SE nicht
18. Mai 2016 um 7:02 Uhr
@HostileFork Fair genug, aber Natürlich die C++-Leute möchten die Verwendung von C++ fördern. Andere sind jedoch anderer Meinung; Linux Torvalds zum Beispiel hat anscheinend mehrere vorgeschlagene Linux-Kernel-Patches abgelehnt, die versuchen, die Kennung zu ersetzen class mit klass um das Kompilieren mit einem C++-Compiler zu ermöglichen. Beachten Sie auch, dass es einige Unterschiede gibt, die Sie stolpern lassen; Beispielsweise wird der ternäre Operator nicht in beiden Sprachen gleich ausgewertet, und die inline Schlüsselwort bedeutet etwas ganz anderes (wie ich aus einer anderen Frage gelernt habe).
– Kyle Strand
28. Juli 2016 um 16:44 Uhr
Bei wirklich plattformübergreifenden Systemprojekten wie einem Betriebssystem sollten Sie sich unbedingt an striktes C halten, da C-Compiler so viel häufiger sind. Bei eingebetteten Systemen gibt es immer noch Plattformen ohne C++-Compiler. (Es gibt Plattformen mit nur passablen C-Compilern!) C++-Compiler machen mich nervös, besonders bei cyberphysischen Systemen, und ich schätze, ich bin nicht der einzige Embedded-Software-/C-Programmierer mit diesem Gefühl.
– niedergeschlagen
16. Mai 2017 um 15:30 Uhr
@downbeat Unabhängig davon, ob Sie C++ für die Produktion verwenden oder nicht, wenn es Ihnen um Strenge geht, dann gibt Ihnen die Möglichkeit, mit C++ zu kompilieren, magische Kräfte für die statische Analyse. Wenn Sie eine Abfrage haben, die Sie an eine C-Codebasis stellen möchten … fragen Sie sich, ob bestimmte Typen auf bestimmte Weise verwendet werden, und lernen Sie, wie man sie verwendet type_traits gezielte Tools dafür bauen können. Was Sie viel Geld für ein statisches Analysetool von C bezahlen würden, kann mit ein wenig C++-Know-how und dem Compiler, den Sie bereits haben, erledigt werden …
– HostileFork sagt, vertraue SE nicht
27. Juli 2018 um 19:57 Uhr
Ich spreche zur Frage von Linux. (Ich habe gerade bemerkt, dass “Linux Torvalds” steht, ha!)
– niedergeschlagen
29. Juli 2018 um 3:05 Uhr
Ich glaube nicht, dass das möglich ist, man könnte es mit doppelten Klammern vortäuschen … solange man die Argumente nicht einzeln braucht.
Wenn der Compiler variadische Makros nicht versteht, können Sie PRINT auch mit einer der folgenden Methoden entfernen:
#define PRINT //
oder
#define PRINT if(0)print
Der erste kommentiert die PRINT-Anweisungen aus, der zweite verhindert die PRINT-Anweisung aufgrund einer NULL-if-Bedingung. Wenn die Optimierung eingestellt ist, sollte der Compiler nie ausgeführte Anweisungen entfernen wie: if(0) print(“hello world”); oder ((leer)0);
wird hier für g++ erklärt, obwohl es Teil von C99 ist und daher für alle funktionieren sollte
#define debug(format, args...) fprintf (stderr, format, args)
Die variadischen Makros von GCC sind keine variadischen C99-Makros. GCC hat C99-Variadic-Makros, aber G++ unterstützt sie nicht, weil C99 kein Teil von C++ ist.
– Chris Lutz
25. März 2009 um 2:17 Uhr
Tatsächlich kompiliert g++ C99-Makros in C++-Dateien. Es wird jedoch eine Warnung ausgeben, wenn es mit ‘-pedantic’ kompiliert wird.
– Alex B
25. März 2009 um 2:24 Uhr
Es ist nicht C99. C99 verwenden VA_ARGS Makro).
– qrdl
25. März 2009 um 5:39 Uhr
C++11 wird ebenfalls unterstützt __VA_ARGS__obwohl sie auch von Compilern in früheren Versionen als Erweiterung unterstützt werden.
– Ethuris
9. Dezember 2016 um 8:58 Uhr
Dies funktioniert nicht für printf(“hi”); wo es keine var args gibt. Gibt es eine allgemeine Möglichkeit, dies zu beheben?
– BTR Naidu
5. April 2017 um 8:50 Uhr
Kateridzhe
• Variable Anzahl von Argumenten wird durch ein Auslassungszeichen (…) gekennzeichnet • Die Syntax von ISO C erfordert mindestens ein festes Argument vor dem ‘…’
Sie können beispielsweise Folgendes eingeben:
#define DEBUGMSG ( int, ...)
Die variadischen Makros von GCC sind keine variadischen C99-Makros. GCC hat C99-Variadic-Makros, aber G++ unterstützt sie nicht, weil C99 kein Teil von C++ ist.
– Chris Lutz
25. März 2009 um 2:17 Uhr
Tatsächlich kompiliert g++ C99-Makros in C++-Dateien. Es wird jedoch eine Warnung ausgeben, wenn es mit ‘-pedantic’ kompiliert wird.
– Alex B
25. März 2009 um 2:24 Uhr
Es ist nicht C99. C99 verwenden VA_ARGS Makro).
– qrdl
25. März 2009 um 5:39 Uhr
C++11 wird ebenfalls unterstützt __VA_ARGS__obwohl sie auch von Compilern in früheren Versionen als Erweiterung unterstützt werden.
– Ethuris
9. Dezember 2016 um 8:58 Uhr
Dies funktioniert nicht für printf(“hi”); wo es keine var args gibt. Gibt es eine allgemeine Möglichkeit, dies zu beheben?
– BTR Naidu
5. April 2017 um 8:50 Uhr
14260600cookie-checkSo erstellen Sie ein variadisches Makro (variable Anzahl von Argumenten)yes
Möchten Sie C oder C++? Wenn Sie C verwenden, warum kompilieren Sie mit einem C++-Compiler? Um richtige variadische C99-Makros zu verwenden, sollten Sie mit einem C-Compiler kompilieren, der C99 unterstützt (wie gcc), nicht mit einem C++-Compiler, da C++ keine standardmäßigen variadischen Makros hat.
– Chris Lutz
25. März 2009 um 2:13 Uhr
Nun, ich nahm an, dass C++ in dieser Hinsicht eine Supermenge von C ist.
– Hasen
25. März 2009 um 3:46 Uhr
tigcc.ticalc.org/doc/cpp.html#SEC13 hat eine detaillierte Erklärung der variadischen Makros.
– Gnubie
25. Oktober 2011 um 9:49 Uhr
Eine gute Erklärung und ein Beispiel finden Sie hier http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
– zafarulq
11. April 2013 um 6:41 Uhr
Für zukünftige Leser: C ist nicht eine Untergruppe von C++. Sie haben viele, viele Dinge gemeinsam, aber es gibt Regeln, die verhindern, dass sie Teilmenge und Obermenge voneinander sind.
– Pharap
9. September 2017 um 0:28 Uhr