Home > Backend Development > C++ > How to Define a Macro That Operates on Arguments Passed to Another Macro in C?

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

Linda Hamilton
Release: 2024-11-15 15:02:03
Original
652 people have browsed it

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 ? ? ? 
Copy after login

Desired Usage:

int a = 1, b = 3, d = 0;
PRINT_ALL(a,b,d);
Copy after login

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 */
Copy after login

Basic Recursion

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

#define MAP_OUT
Copy after login

Considering the following macros:

#define A(x) x B MAP_OUT (x)
#define B(x) x A MAP_OUT (x)
Copy after login

Evaluating A(blah) produces the text:

blah B (blah)
Copy after login

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)
Copy after login

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__)))
Copy after login

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(...)
Copy after login

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)
Copy after login

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__)
Copy after login

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))
Copy after login

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.

The above is the detailed content of How to Define a Macro That Operates on Arguments Passed to Another Macro in C?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template