Is it possible to a Macro evaluate multiple arguments to another?
Asked Answered
U

3

6

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!

Underclassman answered 19/4, 2012 at 18:10 Comment(0)
M
12

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.

Miry answered 19/4, 2012 at 18:14 Comment(0)
D
6

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.

Drum answered 19/4, 2012 at 18:15 Comment(0)
W
1

Adding to James McNellis's answer, if you need to apply this trick to many function-like macros (flm), you could define a single "invoke" macro to do the trick for you. Here's a complete working example:

#include<cstdio>
int f(int x,int y) { return x + y; }
#define g(x,y) x+y
#define XY  1,2
#define _g(arg) g(arg)
#define invoke(flm,...) flm(__VA_ARGS__)
int main(int argc, char ** argv)
{
  printf("%d\n",f(XY));        // functions are easy
  printf("%d\n",_g(XY));       // Jam,es' way
  printf("%d\n",invoke(g,XY)); // with generic invoke flm
  return 0;
}
Wieche answered 21/3, 2014 at 20:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.