2

Is there a way to define a macro that voids variable list of arguments?

#define VOID_ARGS(...) ((void)##__VA_ARGS__)

The use case is void arguments to suppress compiler error [-Werror=unused-value] when warnings treated as errors:

#define DEBUG 1
#ifdef DEBUG
    #define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
    #define func(fmt, ...) VOID_ARGS(fmt, ##__VA_ARGS__)
#endif
hashraf
  • 21
  • 2
  • 3
    What do you mean "voids"? If you don't want to use the arguments, then don't use `__VA_ARGS__`. Also please note that `##__VA_ARGS__` is a non-standard gcc extension. – Lundin Aug 11 '21 at 15:04
  • what exactly do you want to achieve? Please post an example how you would like to use such a macro – Ingo Leonhardt Aug 11 '21 at 15:06
  • 1
    Presumably OP wants to tell the compiler that the arguments are not used so that it does not complain or emit warnings. This can sometimes be done with `(void)unused;` in the body of a function, and OP wants a variadic macro to do this for multiple variables. – Marco Bonelli Aug 11 '21 at 15:07
  • 4
    How about `#define func(fmt, ...) ` without anything after it, e.g. an empty macro? That should replace `func("abc", 4, 3, "bla");` with `;`. – mch Aug 11 '21 at 15:34
  • Does any compiler complain about unused macro arguments? – John Bollinger Aug 11 '21 at 15:43
  • Write a second function that has the same type as `dbg_func()` but that does nothing. – 12431234123412341234123 Aug 11 '21 at 15:45
  • I dunno, @12431234123412341234123. If my code contained variables that were used only for the purpose producing debug messages then I think I would want to be warned about that. Or at least to be able to control such warnings via command-line options. (NMDV, by the way.) – John Bollinger Aug 11 '21 at 15:49
  • @mch empty macro doesn't work because args are not voided. – hashraf Aug 11 '21 at 15:55
  • @12431234123412341234123 thanks! This solves the problem but with overhead of function call. – hashraf Aug 11 '21 at 15:58
  • @hashraf You could use `inline`. – 12431234123412341234123 Aug 11 '21 at 16:01
  • See [`#define` macro for debug printing in C](https://stackoverflow.com/q/1644868/15168) for a detailed discussion of debugging macros — including how to avoid the problems of unused arguments. – Jonathan Leffler Aug 12 '21 at 05:24
  • You could also `(void)` every argument, regardless of `DEBUG`. The Compiler should accept it even when it is used. – 12431234123412341234123 Aug 12 '21 at 16:09

3 Answers3

2

Does this give you an idea how to solve that problem?

debug.h:

extern int dbg_func(const char *format, ...);

//Does nothing
extern int ignoreDebug(const char *format, ...);


#define DEBUG 1

#ifdef DEBUG
    #define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
    #define func(fmt, ...) ignoreDebug(fmt, ##__VA_ARGS__)
#endif

debug.c:

int ignoreDebug(const char *format, ...)
{
  (void)format;
  return 0;
}

int dbg_func(const char *format, ...)
{
  TODO: Some code needs to go here.
  return 0;
}
  • Hmm, why the downvote if the solution works for op? Extra funcall could probably be avioded if one defined `ignoreDebug()` as `static int` or even `static inline int` in debug.h. The optimizer should realize that the call is a NOP and optimize it away. – Ingo Leonhardt Aug 11 '21 at 16:02
1

Rather than attempting to put the debug logic in the function declaration, add it to the function body instead:

int dbg_func(const char *format, ...)
{
#ifdef DEBUG
    // normal debug logic
#else
    (void)format;
    return 0;
#endif
}
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    Depending on the situation, a `static` boolean to enable or disable debug could be even better. – 12431234123412341234123 Aug 11 '21 at 16:28
  • @12431234123412341234123 A `static volatile atomic` one would probably be better. I may be paranoid, but I know compilers are out to get me. Heck, you could make it an `int` and use it to set the current debug/logging level... – Andrew Henle Aug 11 '21 at 16:46
1

I found a way only using the processor. The idea came from this answer https://stackoverflow.com/a/11763277/6082851 The idea is to define a bunch of macros that void the arguments, one macro per possible number of arguments. With the use of __VA_ARGS__, the correct macro can be chosen depending on the number of arguments. Sadly, i didn't found a way to make it recursive so that a limited number of macros can be used for an arbitrary number of arguments, the only way i found was to define a macro for each possible number of arguments. But it can be expanded to an arbitrary amount.

#include <stdio.h>

#ifndef DEBUG
  #define DEBUG 1
#endif

#if DEBUG
  #define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
#else
  //GET_MACRO will get the 6. argument
  #define GET_MACRO(a,b,c,d,e,f,...) f
  //Macros that void a number of arguments
  #define SET_VOID0()  
  #define SET_VOID1(a)          (void)a;
  #define SET_VOID2(a,b)        (void)a;(void)b;
  #define SET_VOID3(a,b,c)      (void)a;(void)b;(void)c;
  #define SET_VOID4(a,b,c,d)    (void)a;(void)b;(void)c;(void)d;
  #define SET_VOID5(a,b,c,d,e)  (void)a;(void)b;(void)c;(void)d;(void)e;
  
  //Void all arguments to avoid compiler warnings.
  //SET_VOID5 is used when there are 5 arguments used, SET_VOID4 when 4 are used, ...
  #define DEBUG_PRINT(...)     GET_MACRO(__VA_ARGS__, SET_VOID5, SET_VOID4, SET_VOID3, SET_VOID2, SET_VOID1, SET_VOID0)(__VA_ARGS__)
#endif



int main(void)
  {
    int foo=5;
    int bar=3;
    DEBUG_PRINT("Foo %i Bar %i\n",foo,bar);
    return 0;
  }