0

I'm familiar with the following way of creating a macro with variable number of arguments. However, consider:

#define MY_MACRO_N(value, format, ...) my_func(value, format, ##__VA_ARGS__)
#define MY_MACRO_0(value) my_func(value, NULL)

Where my_func takes variable number of arguments as well. How can I create a MY_MACRO macro that encapsulates both, such that:

MY_MACRO(my_value);  // expand to my_func(my_value, NULL);
MY_MACRO(my_value, my_format);  // expand to my_func(my_value, my_format);
MY_MACRO(my_value, my_format, a, b);  // expand to my_func(my_value, my_format, a, b);
MY_MACRO();  // invalid

The variable number of arguments break the GET_MACRO approach, however it seems like there should be a way to do this.

8
  • Do you want your macro to accept an arbitrary number of arguments, or is there some fixed upper bound on argument count? Commented Apr 19, 2020 at 14:45
  • No upper bound, as my_func has no upper bound.
    – galah92
    Commented Apr 19, 2020 at 14:47
  • Then I think you're stuck. To the best of my knowledge, all potential approaches to problems of this kind have a built-in maximum on the number of arguments they can handle. You can make that maximum large (typically via large preprocessor code), but you cannot avoid it altogether. Commented Apr 19, 2020 at 14:53
  • 1
    If this is a logging macro with printf-like syntax (and it looks like it) and if you are willing to accept an empty string as default instead of NULL and if you are okay with restricting the format of literal strings if it is given, you can make use of string-literal concatenation. In this special, but common case, the macro looks like #define LOG(CODE, ...) my_func(CODE, "" __VA_ARGS__). (But the format checker will complain about empty format strings, so that may not be a good solution.)
    – M Oehm
    Commented Apr 19, 2020 at 15:10
  • 1
    Well, LOG(X) expands to my_func(X, ""), anything else to my_func(X, "" "<fmt>", ...), which will paste the empty string to your format string, see here. That will only work if your format string is a literal, but that's usually the case. Never mind. It was just a suggestion that you might have found useful.
    – M Oehm
    Commented Apr 19, 2020 at 15:22

1 Answer 1

0

When you overload a macro on number of arguments, be it using an argument list or EVAL(..) recursive expansion, there is always a maximum number of arguments it can handle. You can only set up an unrealistic limit - 64? 256? 1000? - and generate the overloads for that many macro arguments.

#define MY_MACRO_0()                    MY_MACRO_1(will do an error
#define MY_MACRO_1(value)               my_func(value, NULL)
#define MY_MACRO_V(value, format, ...)  my_func(value, format, ##__VA_ARGS__)
#define MY_MACRO_N(_4,_3,_2,_1,_0,N,...)  MY_MACRO_##N
#define MY_MACRO(...)  MY_MACRO_N(0,##__VA_ARGS__,V,V,V,1,0)(__VA_ARGS__)
MY_MACRO(my_value);  // expand to my_func(my_value, NULL);
MY_MACRO(my_value, my_format);  // expand to my_func(my_value, my_format);
MY_MACRO(my_value, my_format, a, b);  // expand to my_func(my_value, my_format, a, b);
MY_MACRO();  // invalid

Still, as noted in the commands, for logging functions it's typical to pass an empty string literal in case of missing format string, then just check if (*fmt == '\0') in the logging function.

#define MY_MACRO(value, ...)   my_func(value, "" __VA_ARGS__)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.