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!

AstroCB
  • 12,337
  • 20
  • 57
  • 73
JaxWR
  • 226
  • 2
  • 7

3 Answers3

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.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
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.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
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;
}
Chris Merck
  • 454
  • 3
  • 12