Is it possible to iterate over arguments in variadic macros?

Viewed 66307

I was wondering if it is possible to iterate over arguments passed to a variadic macro in C99 or using any GCC extensions ?

For e.g. is it possible to write a generic macro that takes a structure and its fields passed as arguments and prints offset of each field within the structure ?

Something like this:

struct a {
    int a;
    int b;
    int c;
};

/* PRN_STRUCT_OFFSETS will print offset of each of the fields 
   within structure passed as the first argument.
*/

int main(int argc, char *argv[])
{
    PRN_STRUCT_OFFSETS(struct a, a, b, c);

    return 0;
}
10 Answers

As https://stackoverflow.com/a/11994395/1938348 do not work well in every case for GCC 12, there is improved version using __VA_OPT__ to remove superfluous commas:

#include <assert.h>

// Make a FOREACH macro
#define FE_0(WHAT)
#define FE_1(WHAT, X) WHAT(X) 
#define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
//... repeat as needed

#define GET_MACRO(_1,_2,_3,_4,_5,NAME,...) NAME 
#define FOR_EACH(action,...) \
  GET_MACRO(__VA_ARGS__ __VA_OPT__(,) FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action __VA_OPT__(,) __VA_ARGS__)




#define F(X) _Generic((X), int:1, long: 2, float: 4),


#define CALL(FF, ...) FF((int[]){ FOR_EACH(F, __VA_ARGS__) 0 } __VA_OPT__(,) __VA_ARGS__)

int foo(int* p, ...){ int i = 0; while(*p != 0) { i += *p; ++p; } return i; }

int main()
{
    assert(CALL(foo) == 0);
    
    assert(CALL(foo, 1) == 1);
    assert(CALL(foo, 1l) == 2);
    assert(CALL(foo, 1.f) == 4);

    assert(CALL(foo, 1.f, 1) == 5);
    assert(CALL(foo, 3l, 1.f, 1) == 7);
}

Working example: https://godbolt.org/z/q7nbj7PxY

Related