Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - Variadic macro which expands into set of macro calls on each argument

I want to have a single macro call which takes in multiple function pointers, and each function pointer is called by a second macro which is a function declaration.

I want two macros on the form

#define FUNCTION_DEF(func) extern int func(void);
#define FUNCTION_DEFS(...) (???)

which is called as such

FUNCTION_DEFS(
    myFunc1,
    myFunc2,

    otherFunc1,
    otherFunc2,

    defaultFunc
)

which expands into

FUNCTION_DEF(myFunc1)
FUNCTION_DEF(myFunc2)

FUNCTION_DEF(otherFunc1)
FUNCTION_DEF(otherFunc2)

FUNCTION_DEF(defaultFunc)

In other words, this single call to FUNCTION_DEFS expands into function declarations of all the variadic arguments.

Currently I'm just skipping the first step and calling FUNCTION_DEF on each function pointer, however a solution to this would be great.

Is this possible?

Edit:

Thanks to @Vality for introducing me to X-Macro. I found this post "Real-world use of X-Macros" which was exactly what I needed.

like image 437
edvardsp Avatar asked Sep 28 '22 05:09

edvardsp


2 Answers

I do not believe what you want precisely is possible using the standard C preprocessor. However a similar solution can be accomplished with X macros.

To do the equivalent of your code using them you would first define the function list as an X macro:

#define FUNCTION_LIST_A \
    X(myFunc1) \
    X(myFunc2) \
    X(otherFunc1) \
    X(otherFunc2) \
    X(defaultFunc)

Then to instantiate these functions with a specific macro you would then define the macro to perform on each function:

#define X(name) FUNCTION_DEF(name)
FUNCTION_LIST_A
#undef X

Which will then expand to:

FUNCTION_DEF(myFunc1)
FUNCTION_DEF(myFunc2)
FUNCTION_DEF(otherFunc1)
FUNCTION_DEF(otherFunc2)
FUNCTION_DEF(defaultFunc)

Hopefully this is useful and close to what you want. Admittedly the syntax is significantly different but if what you wish to accomplish is to apply a chosen function or macro to a whole list of data (in this case function pointers) this is the most idiomatic way I know of to do so using the c preprocessor.

like image 58
Vality Avatar answered Oct 19 '22 20:10

Vality


There are many ways to do this. The most simple is to predefine a version of the loop for each possible length (building on smaller versions), and simply choose the right one based on the number of arguments to iterate over:

#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N

#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_ID(...) __VA_ARGS__

#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)

#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
//...etc

#define FUNCTION_DEF(func) extern int func(void);
#define FUNCTION_DEFS(...) M_FOR_EACH(FUNCTION_DEF, __VA_ARGS__)

You could also cook up a more general solution using traditional recursive techniques, but that usually requires a support library (such as [1], [2]) to provide the mechanism since directly-defined macros don't support recursion.

This is because all looping in the preprocessor has to have a predetermined upper limit, a a consequence of no direct macro recursion: you can either hard-code that limit into your loop implementation in simple cases like the above code, or you can have the recursion-driver underlying your loop-construction operators contain the limit instead, and provide N iterations to constructs that request them (the advantage of the latter is that it lets you centralize, and then forget about, the limit as long as it's high enough, e.g. Order-PP has a limit in the billions of iterations that you won't ever hit in practice).

like image 36
Leushenko Avatar answered Oct 19 '22 20:10

Leushenko