Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to a Macro evaluate multiple arguments to another?

I'd like to do something like this:

#define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
#define MULTIARG()  ARG1, ARG2, ARG3

NEED3ARGS( MULTIARG() )

And I expected it to output something like:

( "[" "ARG1" " + " "ARG2" " + " "ARG3" "]" )

But instead I have:

$ cpp multiarg.c 
# 1 "multiarg.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "multiarg.c"

multiarg.c:4:23: error: macro "NEED3ARGS" requires 3 arguments, but only 1 given
NEED3ARGS

Is there a way to do what I want using ANSI-C/GNU GCC and the C preprocessor?

Thanks!

like image 547
JaxWR Avatar asked Apr 19 '12 18:04

JaxWR


Video Answer


2 Answers

You need some indirection. With C99:

#define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
#define INVOKE_NEED3ARGS(...) NEED3ARGS(__VA_ARGS__)
#define MULTIARG()  ARG1, ARG2, ARG3

INVOKE_NEED3ARGS( MULTIARG() )

(C99 isn't strictly required; you can replace the variadic macro with a fixed-arity macro.)

If you need to compile your source using Visual C++, you'll need even more indirection (because of a compiler bug):

#define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
#define INVOKE_NEED3ARGS_(...) NEED3ARGS __VA_ARGS__
#define INVOKE_NEED3ARGS(...) INVOKE_NEED3ARGS_((__VA_ARGS__))
#define MULTIARG()  ARG1, ARG2, ARG3

INVOKE_NEED3ARGS( MULTIARG() )

As for why indirection is needed: a macro argument is not evaluated and macro-replaced until it is substituted into the replacement list. So, when you try NEED3ARGS(MULTIARG()), MULTIARG() will not be evaluated until after macro invocation has begun, so it's treated as a single argument.

The INVOKE_NEED3ARGS macro ensures that its arguments are completely evaluated before NEED3ARGS is invoked. The __VA_ARGS__ is substituted by the macro-replaced arguments to INVOKE_NEED3ARGS, which is ARG1, ARG2, ARG3, then NEED3ARGS is invoked with those arguments.

like image 143
James McNellis Avatar answered Oct 05 '22 03:10

James McNellis


Yes,

#define NEED3ARGS(a1,a2,a3) ( "[" #a1 " + " #a2 " + " #a3 "]" )
#define MULTIARG()  ARG1, ARG2, ARG3
#define NEED1ARG(ARG) NEED3ARGS(ARG)

NEED1ARG( MULTIARG() )

You need to wrap it in another macro call so the argument gets expanded before NEED3ARGS is called.

like image 22
Daniel Fischer Avatar answered Oct 05 '22 03:10

Daniel Fischer