Heim > Backend-Entwicklung > C++ > Wie definiere ich ein Makro, das mit Argumenten arbeitet, die an ein anderes Makro in C übergeben werden?

Wie definiere ich ein Makro, das mit Argumenten arbeitet, die an ein anderes Makro in C übergeben werden?

Linda Hamilton
Freigeben: 2024-11-15 15:02:03
Original
653 Leute haben es durchsucht

How to Define a Macro That Operates on Arguments Passed to Another Macro in C?

Makros innerhalb von Makroargumenten

Das Problem

Wie kann man ein Makro definieren, das mit den Argumenten arbeitet, die an ein anderes Makro übergeben werden? Berücksichtigen Sie insbesondere Folgendes:

#define PRINT(a) printf(#a": %d", a)
#define PRINT_ALL(...) ? ? ? THE PROBLEM ? ? ? 
Nach dem Login kopieren

Gewünschte Verwendung:

int a = 1, b = 3, d = 0;
PRINT_ALL(a,b,d);
Nach dem Login kopieren

Rekursion erreichen

Rekursive Makros sind in C mithilfe einer unkonventionellen Problemumgehung möglich. Das Ziel besteht darin, ein MAP-Makro zu erstellen, das wie folgt aussieht:

#define PRINT(a) printf(#a": %d", a)
MAP(PRINT, a, b, c) /* Apply PRINT to a, b, and c */
Nach dem Login kopieren

Grundlegende Rekursion

Wir beginnen damit, eine Möglichkeit zu schaffen, etwas auszugeben, das einem Makroaufruf ähnelt, der nicht ausgewertet wird:

#define MAP_OUT
Nach dem Login kopieren

Unter Berücksichtigung der folgenden Makros:

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)
Nach dem Login kopieren

Die Auswertung von A(blah) erzeugt den Text:

blah B (blah)
Nach dem Login kopieren

Der Präprozessor erkennt hier keine Rekursion, da der B (bla) Anruf ist zu diesem Zeitpunkt lediglich Text. Wenn Sie diesen Text zurück in den Präprozessor einspeisen, wird er erweitert:

blah blah A (blah)
Nach dem Login kopieren

Durch die erneute Auswertung dieser Ausgabe wird das Makro A (bla) erweitert und die Rekursion abgeschlossen. Dieser Prozess wird fortgesetzt, bis die Ausgabe erneut in den Präprozessor eingespeist wird.

Um mehrere Auswertungen zu ermöglichen, verwenden wir das EVAL-Makro, um Argumente über eine Kette von Makroaufrufen weiterzuleiten:

#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0 (EVAL0 (EVAL0 (__VA_ARGS__)))
#define EVAL2(...) EVAL1 (EVAL1 (EVAL1 (__VA_ARGS__)))
#define EVAL3(...) EVAL2 (EVAL2 (EVAL2 (__VA_ARGS__)))
#define EVAL4(...) EVAL3 (EVAL3 (EVAL3 (__VA_ARGS__)))
#define EVAL(...)  EVAL4 (EVAL4 (EVAL4 (__VA_ARGS__)))
Nach dem Login kopieren

Jeder level verstärkt den Aufwand seines Vorgängers und wertet die Eingabe letztendlich 365 Mal aus. Beispielsweise ergibt EVAL(A(blah)) 365 Kopien von blah, gefolgt von einem nicht ausgewerteten B (blah). Dieses Setup bietet die Grundlagen für die Rekursion innerhalb bestimmter Stapeltiefenbeschränkungen.

Enderkennung

Die nächste Hürde besteht darin, zu bestimmen, wann die Rekursion beendet werden soll.

Wir definieren ein MAP_END-Makro als die End-of-List-Markierung:

#define MAP_END(...)
Nach dem Login kopieren

Die Auswertung dieses Makros bewirkt nichts und signalisiert das Ende der Rekursion.

Um zwischen den beiden Makros zu wählen, verwenden wir MAP_NEXT, das eine Liste vergleicht Element mit der speziellen End-of-List-Markierung ():

#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(item, next, ...) next MAP_OUT
#define MAP_NEXT1(item, next) MAP_NEXT0 (item, next, 0)
#define MAP_NEXT(item, next)  MAP_NEXT1 (MAP_GET_END item, next)
Nach dem Login kopieren

MAP_NEXT bestimmt, ob basierend auf dem Listenelement und dem nächsten Element fortgefahren oder gestoppt werden soll. Es gibt MAP_END zurück, wenn sie übereinstimmen, oder andernfalls den nächsten Parameter.

Alles zusammenfassen

Mit diesen Komponenten können wir verwendbare Versionen von A und B konstruieren:

#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
Nach dem Login kopieren

Diese Makros wenden eine Operation f auf das aktuelle Listenelement x an und untersuchen dann das nächste Listenelement, peek, um zu bestimmen, ob fortgefahren werden soll oder nicht.

Abschließend fügen wir alles im MAP-Makro der obersten Ebene zusammen:

#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
Nach dem Login kopieren

Dieses Makro fügt am Ende der Liste eine ()-Markierung hinzu, leitet das Ganze durch EVAL und gibt das Ergebnis zurück.

Der Code ist als Bibliothek auf GitHub für verfügbar Ihre Bequemlichkeit.

Das obige ist der detaillierte Inhalt vonWie definiere ich ein Makro, das mit Argumenten arbeitet, die an ein anderes Makro in C übergeben werden?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage