4

I would like to pass 2 arguments to a macro using another macro:

#define A_AND_B     5,1
#define ADD(a, b)   a + b

int add_them(void)
{
    int result = ADD(A_AND_B);
    return result ;
}

I would hope that expands to

int result = 5 + 1;

and I get 6. Instead I get

Error       'ADD' undeclared (first use in this function)   
Error       macro "ADD" requires 2 arguments, but only 1 given  

Is there a way around this?

Kay
  • 123
  • 8
  • Does this answer your question? [Standard alternative to GCC's ##\_\_VA\_ARGS\_\_ trick?](https://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick) – Andrew Jun 02 '22 at 03:57

2 Answers2

3

As is often the case, you need an extra level of (macro) indirection:

#define A_AND_B     5,1
#define ADD(...)    ADD_(__VA_ARGS__)
#define ADD_(a, b)   a + b

int add_them(void)
{
    int result = ADD(A_AND_B);
    return result ;
}

ADD is defined as variadic so that it will work as either ADD(A_AND_B) or ADD(A, B).

This works because __VA_ARGS__ in the replacement body of ADD is replaced with the actual arguments before the replacement body is scanned for macros.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Variadic macros are, currently, non-standards... this is a GCC specific solution. However, the forthcoming C2x will (hopefully) include something similar. See also https://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick – Andrew Jun 02 '22 at 03:56
  • 2
    @andrew: variadic macros have been in C since C99. The problem you reference is a that standardized variadic macros prior to C2x don't allow the variadic arguments to be omitted. That does not apply to this answer; my variadic macro is not intended to be invoked with no arguments. – rici Jun 02 '22 at 04:20
1

Per C 2018 6.10.3.1, a compiler first identifies the arguments for a function-like macro and then performs macro replacement on the arguments, followed by macro replacement for the function-like macro. This means that, in ADD(A_AND_B), the argument is identified as A_AND_B before it is replaced with 5,1. As the macro invocation has only this single argument and the macro is defined to have two parameters, an error is diagnosed.

Given your definition of ADD, there is no way to change this behavior in a compiler that conforms to the C standard.

You can instead use another macro to expand the arguments and apply the desired macro:

#define Apply(Macro, Arguments) Macro(Arguments)

then int result = Apply(ADD, A_AND_B); will work. That will identify ADD and A_AND_B as arguments to Apply. Then it will expand those, producing an unchanged ADD and 5,1. Then the macro replacement for Apply produces ADD(5,1). Then this is again processed for macro replacement, which replaces ADD(5,1) in the ordinary way.

Note that good practice is usually to define ADD as #define ADD(a, b) ((a) + (b)) to avoid unexpected interactions with other operators neighboring the use of the macro.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312