17

A well-known and portable way to suppress C compiler warnings about unused variables is (see unused parameter warnings in C code):

#define UNUSED(x) (void)(x)

I'm looking for a way to generalize this to take multiple inputs (of different type):

void foo(int a, long b, void* c){

   /* Want this: */
   ALL_UNUSED(a, b, c);

   /* instead of: */
   UNUSED(a);
   UNUSED(b);
   UNUSED(c);
}

One way that seems to do the trick is to use a variadic function

static inline void ALL_UNUSED(int dummy, ...) {}

However, I suspect this solution is objectionable in the expert eye.

Is there a standard-compliant and portable (i.e. not using __attribute__((unused))) way to make a variadic UNUSED() function/macro? Many thanks!

EDIT

There does not seem to exist a clean way of doing what I asked for in the context of C99 or the C preprocessor. Such is life.

In his answer below, @Dabo shows a pretty interesting way of doing what I asked for using a series of macros. This is neat and informative (at least to me), so I accept that answer. That said, I would not deploy it in a big project because it's tearse enough to outweigh the benefit it brings (in my eyes). But people will come to different conclusions here.

As noted below, the approach of using an empty variadic function is not perfect either. While it's a pretty elegant one-liner, it will provoke warnings about unititialized variables (if they are). Also, you have to trust your compiler to completely optimize it away, which I object to in principle but that all compilers I have tried with actually do.

One relevant case is when stubbing functions after an early high-level interface design phase. Then your unused variables will all be function arguments and initialized by definition, and the following approach works fine

static inline void UNUSED(int dummy, ...) {}

void foo(int a, long b, void* c){
    UNUSED(a, b, b); /* No warnings */
}
Community
  • 1
  • 1
dag
  • 192
  • 1
  • 7
  • 3
    What about using `#define UNUSED(...) (void)(__VA_ARGS__)`. – 0xF1 Apr 23 '14 at 05:59
  • 3
    Sadly no -- tried it. The compiler will warn about an unused expression result or a "value as statement". Semantically, what do you expect (void) (a, b, c); to mean? – dag Apr 23 '14 at 06:07
  • 1
    Thanks for pointing that out. Trying some other way... – 0xF1 Apr 23 '14 at 06:10
  • Can anyone please elaborate the problems with variadic function? – 0xF1 Apr 23 '14 at 06:11
  • @MadHatter I'm looking now at [iterate over arguments in variadic macros](http://stackoverflow.com/a/1872506/2549281). I think it might be helpful. – Dabo Apr 23 '14 at 06:20
  • @Dabo : Thanks for the link. I think it may help. – 0xF1 Apr 23 '14 at 06:32
  • 1
    Note gcc has the option `-Wno-unused-variable` which seems to do what you asking? Although maybe the question is more about varadics an macros ... – spinkus Apr 23 '14 at 07:20
  • I have updated my answer with a possible solution. – 0xF1 Apr 23 '14 at 09:19
  • @dag we're not worried about its semantics, we're just looking for a hack to suppress a compiler warning – M.M Apr 25 '14 at 04:21
  • @MadHatter if the variadic function actually causes your compiler to suppress the warnings then go for it – M.M Apr 25 '14 at 04:22
  • 1
    `#define UNUSED(x) (void)(x)` actually **evaluates** 'x' ... `#define UNUSED(x) (void)(sizeof(x))` is also not a perfect solution since C99 introduced famous VLA's (Variable Length Arrays) which also do get evaluated when passed to the `sizeof()` ... –  Sep 12 '18 at 10:52

7 Answers7

9

Based on these two posts Variadic macro to count number of arguments, and Overloading macros i made the following

#define UNUSED1(x) (void)(x)
#define UNUSED2(x,y) (void)(x),(void)(y)
#define UNUSED3(x,y,z) (void)(x),(void)(y),(void)(z)
#define UNUSED4(a,x,y,z) (void)(a),(void)(x),(void)(y),(void)(z)
#define UNUSED5(a,b,x,y,z) (void)(a),(void)(b),(void)(x),(void)(y),(void)(z)

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5, N,...) N
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)

#define ALL_UNUSED_IMPL_(nargs) UNUSED ## nargs
#define ALL_UNUSED_IMPL(nargs) ALL_UNUSED_IMPL_(nargs)
#define ALL_UNUSED(...) ALL_UNUSED_IMPL( VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__ )

what can be used as follows

 int main()
 {
    int a,b,c;
    long f,d;

    ALL_UNUSED(a,b,c,f,d);

    return 0;
  }

eclipse macro expansion gives :

  (void)(a),(void)(b),(void)(c),(void)(f),(void)(d)

compiled with gcc -Wall with no warnings

EDIT:

#define UNUSED1(z) (void)(z)
#define UNUSED2(y,z) UNUSED1(y),UNUSED1(z)
#define UNUSED3(x,y,z) UNUSED1(x),UNUSED2(y,z)
#define UNUSED4(b,x,y,z) UNUSED2(b,x),UNUSED2(y,z)
#define UNUSED5(a,b,x,y,z) UNUSED2(a,b),UNUSED3(x,y,z)

EDIT2

As for inline method you posted, a quick test

int a=0;
long f,d;

ALL_UNUSEDINLINE(a,f,&d);

gives ‘f’ is used uninitialized in this function [-Wuninitialized] warning. So here at least one use case which breaks generality of this aproach

Dabo
  • 2,371
  • 2
  • 18
  • 26
  • Quite nice! I will play around with this and see how it feels. The manual enumeration seems unavoidable, but hardly makes anyone fall in love with cpp. Thanks! – dag Apr 23 '14 at 08:38
  • 1
    can I ask what your opinion is of the void variadic function approach that I mention in the post (which is somewhat shorter than your impressive macro solution)? Does it strike you as incorrect and/or flawed? – dag Apr 23 '14 at 08:42
  • 1
    @dag see my edit2 regarding `inline`, i assume it answers your question. – Dabo Apr 23 '14 at 11:12
  • Thanks for pointing that out! The (unstated) usecase I had in mind was actually just to suppress warnings from unused function arguments. – dag Apr 25 '14 at 04:12
4

I took Dabo's (https://stackoverflow.com/a/23238813/5126486) awesome solution and improved a little bit so it's easier to extend to more than 5:

#define UNUSED0()
#define UNUSED1(a)                  (void)(a)
#define UNUSED2(a,b)                (void)(a),UNUSED1(b)
#define UNUSED3(a,b,c)              (void)(a),UNUSED2(b,c)
#define UNUSED4(a,b,c,d)            (void)(a),UNUSED3(b,c,d)
#define UNUSED5(a,b,c,d,e)          (void)(a),UNUSED4(b,c,d,e)

#define VA_NUM_ARGS_IMPL(_0,_1,_2,_3,_4,_5, N,...) N
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(100, ##__VA_ARGS__, 5, 4, 3, 2, 1, 0 )

#define ALL_UNUSED_IMPL_(nargs) UNUSED ## nargs
#define ALL_UNUSED_IMPL(nargs) ALL_UNUSED_IMPL_(nargs)
#define ALL_UNUSED(...) ALL_UNUSED_IMPL( VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__ )
Michael
  • 2,118
  • 1
  • 19
  • 25
kugel
  • 61
  • 2
2

Here is a very simple approach that does not require any special tricks nor does it incur any runtime overhead.

Original Answer (C++ only)

#define UNUSED(...) (void)sizeof(__VA_ARGS__)

https://godbolt.org/z/Gz8MfvaTz

Updated Answer (C and C++)

I had forgotten to change the compiler from C++ to C, and thus the revised answer.

int main(int argc, char ** argv)
{
    /* different types */
    UNUSED(argc, argv);

    /* many variables */
    int w, x, y, z;
    UNUSED(w, x, y, z);

    /* single variable */
    void * ptr;
    UNUSED(ptr);
}

MSVC
/O2 /W4
No warnings from C and C++ compilers.

Clang
-O3 -Wall -Wextra
No warnings from C and C++ compilers.

GCC
-O3 -Wall -Wextra
No warnings from C++ compiler only. For the C compiler, only the last parameter is ignored without warning. So at worst case, this version of UNUSED is on par with the traditional #define UNUSED(x) ((void)x).

Matt Eding
  • 917
  • 1
  • 8
  • 15
1

What do you think about this:

#define UNUSED(...) [__VA_ARGS__](){};

Example:

void f(int a, char* b, long d)
{
    UNUSED(a, b, d);
}

Should be expanded ad a lambdas definition:

[a,b,d](){}; //optimized by compiler (I hope!)

===== Tested with http://gcc.godbolt.org ===== I've tryed with this code:

#define UNUSED(...) [__VA_ARGS__](){};

int square(int num, float a) {
  UNUSED(a);
  return num * num;
}

The resulting output (compiled with -O0 -Wall) is:

square(int, float):
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movss   %xmm0, -8(%rbp)
    movl    -4(%rbp), %eax
    imull   -4(%rbp), %eax
    popq    %rbp
    ret

EDIT:

If you can use C++11 this could be a better solution :

template <typename ...Args>
void UNUSED(Args&& ...args)
{
    (void)(sizeof...(args));
}
Gian Lorenzo Meocci
  • 1,136
  • 2
  • 14
  • 23
0

The following causes no warnings with -Wall -Wextra on both GCC and Clang, but only works for C11 and higher:

#define UNUSED(...) ((void)sizeof((_Bool[]){__VA_ARGS__}))
yyny
  • 1,623
  • 18
  • 20
  • That depends on the types of passed parameters, doesn't it? They might not have the same and compatible types that are allowed as initializers for the array thus creating another warning or even errors, e.g., when passing string literals you would get "array of inappropriate type initialized from string constant". Also, why would this require C11? – stefanct Sep 23 '22 at 22:19
  • I don't get this error with string literals, but yes, this only works for some types since struct and union types are not convertible to `_Bool`, so you will have to take the address of variables with those types. The macro requires C11 because compound literals (`(_Bool[]){__VA_ARGS__}`) were added in C11, if your project does not use C11 (or later), you will have to resort to a less minimal solution. I like this solution because all my projects are C11, and because unused structs and unions (not pointers) are very rare. – yyny Sep 28 '22 at 15:26
  • Compound literals have been added in C99. – stefanct Sep 29 '22 at 16:08
0

A little refined version of the solution in the question that accepts any type of arguments:

static inline void UNUSED2(int dummy, ...)
{
    (void)dummy;
}
#define UNUSED(...) UNUSED2(0, __VA_ARGS__)

Seems to be working with several compilers, not only GCC.

vjalle
  • 549
  • 4
  • 13
-2

You can use compile time __VA_ARGS__ macro.

#define UNUSED(...) (void)(__VA_ARGS__)

UPDATE: After lot of trials, I came up to an optimized solution:

#define UNUSED(...)  __VA_ARGS__

int main()
{
    int e, x;
    char **a, **b, *c, d[45];
    x = x, UNUSED(a, b, c, d, e), x; 

    return 0;
}

NOTES:

  1. It doesn't eliminate warnings completely but reduces them to just 3 same type of warnings:
    warning: value computed is not used

  2. The first and last x ensure assignment of same datatypes.

  3. I will say it is optimized because for any number of unused variables it gives 3 warnings (I may be wrong, please test it yourself and do report me if you get more) and the amount of code (MACRO manipulations) required to achieve it is less.

  4. I am still working on it, will post if I reach to any better solution.

0xF1
  • 6,046
  • 2
  • 27
  • 50
  • Thanks @MadHatter, but I think both Clang and GCC still emit warnings with this. GCC "warning: left-hand operand of comma expression has no effect [-Wunused-value]", Clang: "warning: expression result unused [-Wunused-value]" – dag Apr 23 '14 at 06:12
  • 2
    Ya!! I compiled it myself with `gcc -Wall` and got same warning. Still trying something ... – 0xF1 Apr 23 '14 at 06:17