In C programming, it is not straightforward to apply macros recursively to macro arguments. However, employing a complex workaround, it is possible to achieve a MAP macro with the desired functionality.
To initiate the recursion, we define a MAP_OUT macro that serves as a placeholder for macro expansion:
#define MAP_OUT
Next, we create two macros, A and B, to demonstrate recursion:
#define A(x) x B MAP_OUT (x) #define B(x) x A MAP_OUT (x)
Evaluating A(blah) results in the following output:
blah B (blah)
The preprocessor treats B(blah) as plain text since it is not yet a macro call. When this text is reprocessed, it expands to produce:
blah blah A (blah)
By continuously feeding the output back into the preprocessor, we can sustain the recursion indefinitely.
To automate this repeated evaluation, we use the EVAL macro:
#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__)))
The EVAL macro propagates its arguments through a tree of macro calls, multiplying their evaluation count by 365.
To prevent endless recursion, we need a mechanism for termination. We define a special macro named MAP_END:
#define MAP_END(...)
When evaluated, this macro does nothing, effectively stopping the recursion.
To select between recursive and terminating macros, we introduce 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 compares the current item with the end-of-list marker (). It returns MAP_END if they match, or the next parameter otherwise.
Combining these elements, we can create practical versions of the A and B macros:
#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 and MAP1 apply the operation f to the current item x. They then check the next item, peek, to determine whether to continue or end the recursion.
Finally, we tie everything together with the top-level MAP macro:
#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
MAP places an end-of-list marker on the argument list and passes it through EVAL.
By utilizing these techniques, you can achieve recursive macro functionality in C, enabling complex macro-based processing.
The above is the detailed content of How can you achieve recursive macro functionality in C, despite the limitations of macro expansion?. For more information, please follow other related articles on the PHP Chinese website!