Named parameters in C 2014-07-14

C99 introduced the concept of designated initializers, that allows to initialize a structure using the name of the fields, like this:

struct MyStruct {int x; float y;}; struct MyStruct a = { .x = 10, .y = 3.6, };

Here is a C macro that extends this syntax to function calls.

I present it as a curiosity, and I really wouldn't advise anybody to actually use it in a project (except maybe for very special cases, like for example emulating the interface of a language that accepts named arguments).

The macro is using a few tricks, notably the 'foreach' as described in this stack overflow question.

[Edit] As some people pointed out on the hacker news thread, the macro also uses a statement expression, which is a GNU C extension, and so it would probably not work with MSVC (I am not going to try).

#define FE_0(a, a0, X) a0(0, X) #define FE_1(a, a0, X, ...) a(1, X)FE_0(a, a0, __VA_ARGS__) #define FE_2(a, a0, X, ...) a(2, X)FE_1(a, a0, __VA_ARGS__) #define FE_3(a, a0, X, ...) a(3, X)FE_2(a, a0, __VA_ARGS__) #define FE_4(a, a0, X, ...) a(4, X)FE_3(a, a0, __VA_ARGS__) #define GET_MACRO(_0, _1, _2, _3, _4, NAME,...) NAME #define FOR_EACH(a, a0, ...) \ GET_MACRO(__VA_ARGS__, FE_4, FE_3, FE_2, FE_1, FE_0) \ (a, a0, __VA_ARGS__) #define ARGS_STRUCT_ATTR(n, attr) union {attr, _##n;}; #define ARGS_STRUCT(...) \ struct { \ FOR_EACH(ARGS_STRUCT_ATTR, ARGS_STRUCT_ATTR, \ __VA_ARGS__) \ } #define ARGS_PASS(n, attr) _args._##n, #define ARGS_PASS0(n, attr) _args._##n #define PASS_STRUCT(...) \ FOR_EACH(ARGS_PASS, ARGS_PASS0, __VA_ARGS__) #define CALL_NAMED_ARGS(func, args, ...) ({ \ ARGS_STRUCT args _args = {__VA_ARGS__}; \ func(PASS_STRUCT args); \ })

And here is how we can use it:

// A normal C function. float func(int x, float y) { printf("%d %f

", x, y); return x + y; } // func2 will call `func` using named arguments. #define func2(...) \ CALL_NAMED_ARGS(func, (int x, float y), __VA_ARGS__) int main() { float ret = func2(.y = 1.5, .x = 20); }

For the curious, here is what the macro expends to:

float ret = ({ struct { union {int x, _1;}; union {float y, _0;}; } _args = { .y = 1.5, .x = 20 }; func(_args._1,_args._0); });

The macro can only support up to 5 arguments (but, could easily be extended for more). One interesting thing is that if we omit a parameter it will be automatically set to 0. So let say you have a function like:

void func(int x0, int x1, int x2, int x3, int x4);

And you want to call it by setting most of the arguments to 0. You could do: