Heim > Artikel > Backend-Entwicklung > Wie können Sie trotz der Einschränkungen der Makroerweiterung eine rekursive Makrofunktionalität in C erreichen?
In der C-Programmierung ist es nicht einfach, Makros rekursiv auf Makroargumente anzuwenden. Mit einer komplexen Problemumgehung ist es jedoch möglich, ein MAP-Makro mit der gewünschten Funktionalität zu erreichen.
Um die Rekursion zu initiieren, definieren wir ein MAP_OUT-Makro, das als Platzhalter für dient Makroerweiterung:
#define MAP_OUT
Als nächstes erstellen wir zur Demonstration zwei Makros, A und B Rekursion:
#define A(x) x B MAP_OUT (x) #define B(x) x A MAP_OUT (x)
Die Auswertung von A(blah) führt zur folgenden Ausgabe:
blah B (blah)
Der Präprozessor behandelt B(blah) als Klartext, da es sich noch nicht um einen Makroaufruf handelt. Wenn dieser Text erneut verarbeitet wird, wird er erweitert, um Folgendes zu erzeugen:
blah blah A (blah)
Durch die kontinuierliche Rückführung der Ausgabe in den Präprozessor können wir die Rekursion auf unbestimmte Zeit aufrechterhalten.
Um diese wiederholte Auswertung zu automatisieren, verwenden wir das EVAL-Makro:
#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__)))
Das EVAL-Makro propagiert seine Argumente durch einen Baum von Makroaufrufen und multipliziert deren Auswertungsanzahl mit 365.
Um eine endlose Rekursion zu verhindern, benötigen wir einen Mechanismus zur Beendigung. Wir definieren ein spezielles Makro mit dem Namen MAP_END:
#define MAP_END(...)
Bei der Auswertung führt dieses Makro nichts aus und stoppt effektiv die Rekursion.
Um zwischen rekursiven und terminierenden Makros zu wählen, führen wir MAP_NEXT:
#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)MAP_NEXT vergleicht das aktuelle Element mit der End-of-List-Markierung (). Es gibt MAP_END zurück, wenn sie übereinstimmen, oder andernfalls den nächsten Parameter.Praktische ImplementierungDurch die Kombination dieser Elemente können wir praktische Versionen der A- und B-Makros erstellen:
#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__)MAP0 und MAP1 wenden die Operation f auf das aktuelle Element x an. Anschließend überprüfen sie das nächste Element, Peek, um zu bestimmen, ob die Rekursion fortgesetzt oder beendet werden soll.Schließlich verknüpfen wir alles mit dem MAP-Makro der obersten Ebene:
#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))MAP-Orte eine End-of-List-Markierung auf der Argumentliste und leitet sie durch EVAL.Durch die Verwendung dieser Techniken können Sie rekursive Makrofunktionalität in C erreichen und so komplexe Makrobasierte Verarbeitung.
Das obige ist der detaillierte Inhalt vonWie können Sie trotz der Einschränkungen der Makroerweiterung eine rekursive Makrofunktionalität in C erreichen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!