Home > other >  Suppressing "variable set but not used" warnings in the disabled case of a debug printf ma
Suppressing "variable set but not used" warnings in the disabled case of a debug printf ma

Time:06-17

There are a ton of questions about suppressing "variable set but not used" warnings, but I haven't found one that addresses my very specific problem, which is a debugging macro defined as follows:

#ifdef DEBUG
# define dbg_printf(...) ((void)printf(__VA_ARGS__))
#else
# define dbg_printf(...) ((void)( /* ??? */ ))
#endif

A variable that is set unconditionally, and then used only as one of the arguments to dbg_printf, should not trigger "variable set but not used" warnings, whether or not DEBUG is defined. It should not be necessary to annotate such variables at the point of definition. For example, this should be warning-free:

struct Thing { int value; struct Thing *next; };
struct Thing *find_first_match(int n, struct Thing *list)
{
    struct Thing *p;
    int searched = 0;
    for (p = list; p; p = p->next) {
        searched  ;
        if (p->value == n) break;
    }
    dbg_printf("%s: %s after scanning %d entries\n",
               __func__, p ? "found" : "not found", searched);
    return p;
}

I have tried a couple things in place of the /* ??? */, but nothing I have tried so far has worked without undesirable side effects:

  1. # define dbg_printf(...) ((void)(0 && (__VA_ARGS__)))

    Causes some versions of clang to complain about unused values, e.g.

    void foo(void) {
      dbg_printf("%d\n", 23);
    }
    

    test.c:4:14: warning: expression result unused [-Wunused-value]
      dbg_printf("%d\n", 23);
                 ^~~~~~
    
  2. # define dbg_printf(...) ((void)(sizeof(__VA_ARGS__)))

    Causes some versions of clang to complain about misuse of sizeof, e.g. same test case

    test.c:4:14: warning: sizeof on pointer operation will return size of 'const char *'
                          instead of 'const char [4]' [-Wsizeof-array-decay]
      dbg_printf("%d\n", 23);
                 ^~~~~~
    
  3. [Edited to add:] An inline variadic function that does nothing, instead of a macro, e.g.

    static inline void dbg_printf(const char *msg, ...) {
      (void)msg;
    }
    

    is no good because its arguments will still be evaluated for their side effects, and the offending code base has lots of instances of stuff like

      // code that mutates a global data structure, and then ...
      dbg_printf("validation status after %s: %s\n", __func__,
                 expensive_global_data_structure_validation());
    

Please suggest a construct that can be used in place of the /* ??? */ that will suppress "variable set but not used" warnings without introducing other spurious diagnostics in their place. If this can be done with strictly conforming C2011 code, that is preferable. Compiler extensions are acceptable if and only if they work correctly on all four of:

  • gcc 4.8
  • gcc 9.x
  • clang 7.0
  • clang 10.0

Yes, we are stuck using old compilers for good reasons, or at least reasons which nobody has the spare cycles to overcome.

CodePudding user response:

I use this trick to disable such warnings:

#ifdef DEBUG
# define dbg_printf(...) ((void)printf(__VA_ARGS__))
#else
# define dbg_printf(...) do { if ((0)) (void)printf(__VA_ARGS__); } while (0)
#endif

This macro generates no code in optimized builds but does not complain about variables initialized and only used inside the argument list.

CodePudding user response:

This will work:

#ifdef DEBUG
# define dbg_printf(...) ((void)printf(__VA_ARGS__))
#else
# define dbg_printf(...) ((void)(0 && printf(__VA_ARGS__)))
#endif

As the right-hand side of the && operator won't be evaluated.

Alternately:

#ifdef DEBUG
# undef DEBUG
# define DEBUG 1
#else
# define DEBUG 0
#endif

Then:

#define dbg_printf(...) ((void)(DEBUG && printf(__VA_ARGS__)))

That way you have if multiple such definitions depending on DEBUG you only need a single #ifdef.

  •  Tags:  
  • c
  • Related