Maison > développement back-end > C++ > Comment définir une macro qui fonctionne sur les arguments passés à une autre macro en C ?

Comment définir une macro qui fonctionne sur les arguments passés à une autre macro en C ?

Linda Hamilton
Libérer: 2024-11-15 15:02:03
original
702 Les gens l'ont consulté

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

Macros Within Macro Arguments

The Problem

How can one define a macro that operates on the arguments passed to another macro? Specifically, consider the following:

#define PRINT(a) printf(#a": %d", a)
#define PRINT_ALL(...) ? ? ? THE PROBLEM ? ? ? 
Copier après la connexion

Desired Usage:

int a = 1, b = 3, d = 0;
PRINT_ALL(a,b,d);
Copier après la connexion

Achieving Recursion

Recursive macros are possible in C using an unconventional workaround. The goal is to create a MAP macro that resembles:

#define PRINT(a) printf(#a": %d", a)
MAP(PRINT, a, b, c) /* Apply PRINT to a, b, and c */
Copier après la connexion

Basic Recursion

We begin by creating a way to output something resembling a macro call that isn't evaluated:

#define MAP_OUT
Copier après la connexion

Considering the following macros:

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)
Copier après la connexion

Evaluating A(blah) produces the text:

blah B (blah)
Copier après la connexion

The preprocessor doesn't detect recursion here, as the B (blah) call is merely text at this stage. Feeding this text back into the preprocessor expands it:

blah blah A (blah)
Copier après la connexion

Evaluating this output again expands the A (blah) macro, completing the recursion. This process continues until the output is fed back into the preprocessor again.

To facilitate multiple evaluations, we use the EVAL macro to pass arguments down a chain of macro calls:

#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__)))
Copier après la connexion

Each level amplifies the effort of its predecessor, ultimately evaluating the input 365 times. For example, EVAL(A(blah)) yields 365 copies of blah followed by an unevaluated B (blah). This setup provides the fundamentals for recursion within certain stack depth limitations.

End Detection

The next hurdle is determining when to terminate the recursion.

We define a MAP_END macro as the end-of-list marker:

#define MAP_END(...)
Copier après la connexion

Evaluating this macro does nothing, signaling the end of recursion.

To choose between the two macros, we use MAP_NEXT, which compares a list item with the special end-of-list marker ():

#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)
Copier après la connexion

MAP_NEXT determines whether to continue or stop based on the list item and the next item. It returns MAP_END if they match or the next parameter otherwise.

Putting it All Together

With these components, we can construct usable versions of A and B:

#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__)
Copier après la connexion

These macros apply an operation f to the current list item x and then examine the next list item, peek, to determine whether to continue or not.

Finally, we assemble everything in the top-level MAP macro:

#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
Copier après la connexion

This macro adds a () marker at the end of the list and passes the whole thing through EVAL, returning the result.

The code is available as a library on GitHub for your convenience.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal