Home Variable arguments inside a macro
Reply: 3

Variable arguments inside a macro

Sruthy
1#
Sruthy Published in 2017-12-06 12:47:25Z

I have two functions foo1(a,b) & foo2(a,b,c) and a macro

#define add(a,b) foo(a,b)

I need to re-define macro to accomplish,

1.if add() is called with 2 parameters, then call foo1

  1. if add() is called with 3 parameters then call foo2

Im new to the option VA_ARGS. How can I do that

Lundin
2#
Lundin Reply to 2017-12-06 15:44:36Z

If you must use variadic macros, then here is a trick.

#define add(...) _Generic ( &(int[]){__VA_ARGS__}, \
                            int(*)[2]: add2,       \
                            int(*)[3]: add3) (__VA_ARGS__)
  • Have the macro create a compound literal array. The size of this array will depend on the number of arguments.
  • Grab the address of the compound literal, to get an array pointer type.
  • Let _Generic check which type you got, then call the proper function based on that.

This is 100% standard C and also type safe.


Demo:

#include <stdio.h>


#define add(...) _Generic ( &(int[]){__VA_ARGS__}, \
                            int(*)[2]: add2,       \
                            int(*)[3]: add3) (__VA_ARGS__)

int add2 (int a, int b);
int add3 (int a, int b, int c);

int main (void)
{
  printf("%d\n", add(1, 2));
  printf("%d\n", add(1, 2, 3));
//printf("%d\n", add(1, 2, 3, 4)); Compiler error for this.
}


int add2 (int a, int b)
{
  return a + b;
}

int add3 (int a, int b, int c)
{
  return a + b + c;
}
StoryTeller
3#
StoryTeller Reply to 2017-12-06 13:20:52Z

That usual trick for counting arguments may be adapted for this:

#define ADD_EXPAND(...) \
        ADD_EXPAND_(__VA_ARGS__, EXPAND_ADD_FUNCS())

#define ADD_EXPAND_(...) \
        EXPAND_ADD_SEL_FUNC(__VA_ARGS__)

#define EXPAND_ADD_SEL_FUNC(first_, second_, third_, func, ...) func

#define EXPAND_ADD_FUNCS() foo2, foo, dummy

#define add(...) ADD_EXPAND(__VA_ARGS__)(__VA_ARGS__)

Once you plow through the boiler plate, it basically just involves placing all the arguments in a line, with the function tokens after them, and seeing which function stands out. That's what EXPAND_ADD_SEL_FUNC does.

You can see it live on coliru.

But I'll reiterate what we told you in comments. This is likely to be a sub-par solution to a proper function. I haven't tested it thoroughly, so breakage is easily possible. Use at your own risk.

M Oehm
4#
M Oehm Reply to 2017-12-07 13:31:52Z

If you just want to distinguish between two functions, the following works:

#define ADD(_1, _2, _3, X, ...) X
#define add(...) ADD(__VA_ARGS__, add3, add2, 0)(__VA_ARGS__)

The auxiliary macro ADD always picks the fourth argument:

add(a, b)    --> ADD(a, b, add3, add2, 0)    --> add2
add(a, b, c) --> ADD(a, b, c, add3, add2, 0) --> add3

The drawback is that you get quite cryptic error messages when you don't supply two or three arguments to the function.

The advantage over variadic functions is that you get type safety. For example if your functions operate on doubles, you can still say add(1, 2) and the integer arguments will be converted to doubles. And variadic functions require some additional information on the number of actual arguments, so that's not a feasible solution here, unless you specify the number of summands in the function.

Addendum: I've changed the add macro so that it doesn't pass an empty variadic list to ADD. Some compilers allow empty lists, but it isn't standard C.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.349007 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO