Just a few years late at this point, but I have some interesting contributions. In this case, I would use the pre-processor. Be warned of incorrect types with variadics btw.
Note: Parenthesizing the function name will make macros ignore it while allowing the file symbols to not be different than the API (other than macro usage).
Method 1: Sentinel Macro
Mask your functions as so:
#define my_func(...) my_func(__VA_ARGS__, NULL);
void (my_func)(...)
{
/* ... */
}
Method 2: Array Length Macro
Cast the variadic to a int[]
, to statically determine sizeof
said array:
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
#define NARGS(...) ARRAY_LENGTH((int[])({ __VA_ARGS__ }))
Similarly mask, but add a count argument in front:
#define my_func(...) my_func(NARGS(__VA_ARGS__), __VA_ARGS__);
void (my_func)(int n, ...)
{
/* ... */
}
Compile-Specific Type Checking For the Array Macro:
Outside the scope of the question, but since I'm on a roll.
I always use GCC, and sometimes utilize the following. I believe there are semi-compatible features in Clang, but I'm not sure. This allows you to be sure an actual array is being passed and not a pointer.
#define TYPE_COMPATABLE(x, y) __builtin_types_compatible_p(__typeof__(x), __typeof__(y))
#define CHOOSE_EXPR(b, x, y) __builtin_choose_expr((b), (x), (y))
#define IS_ARRAY(a) (!TYPE_COMPATABLE((a), &(a)[0]))
#define ARRAY_LENGTH(a) \
({ \
_Static_assert(IS_ARRAY(a), "non-array"); \
sizeof(a) / sizeof((a)[0]); \
})
#define NARGS(...) ARRAY_LENGTH((int[])({ __VA_ARGS__ }))
At that point, might just use C++ hehe.