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

不问归期 提交于 2019-12-07 09:56:43

问题


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.


回答1:


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.




回答2:


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).



来源:https://stackoverflow.com/questions/31654930/c-variadic-macro-which-expands-into-set-of-macro-calls-on-each-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!