So erstellen Sie ein variadisches Makro (variable Anzahl von Argumenten)

Lesezeit: 7 Minuten

hasens Benutzeravatar
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.

    – 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

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

Benutzeravatar von cmccabe
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.

#define macro(ARGS) some_complicated (whatever ARGS)
// ...
macro((a,b,c))
macro((d,e))

  • Obwohl es möglich ist, ein variadisches Makro zu haben, ist die Verwendung von doppelten Klammern ein guter Rat.

    – David Rodríguez – Dribeas

    25. März 2009 um 7:06 Uhr

  • Der XC-Compiler von Microchip unterstützt keine Variadic-Makros, daher ist dieser Trick mit doppelten Klammern das Beste, was Sie tun können.

    – gbmhunter

    20. Juli 2016 um 2:27 Uhr

#define DEBUG

#ifdef DEBUG
  #define PRINT print
#else
  #define PRINT(...) ((void)0) //strip out PRINT instructions from code
#endif 

void print(const char *fmt, ...) {

    va_list args;
    va_start(args, fmt);
    vsprintf(str, fmt, args);
        va_end(args);

        printf("%s\n", str);

}

int main() {
   PRINT("[%s %d, %d] Hello World", "March", 26, 2009);
   return 0;
}

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

http://www.delorie.com/gnu/docs/gcc/gcc_44.html

schnelles Beispiel:

#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

Benutzeravatar von Kateridzhe
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

1426060cookie-checkSo erstellen Sie ein variadisches Makro (variable Anzahl von Argumenten)

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

Privacy policy