问题
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 */
}
回答1:
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
回答2:
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));
}
回答3:
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__ )
回答4:
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:
It doesn't eliminate warnings completely but reduces them to just
3
same type of warnings:warning: value computed is not used
The first and last
x
ensure assignment of same datatypes.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.I am still working on it, will post if I reach to any better solution.
来源:https://stackoverflow.com/questions/23235910/variadic-unused-function-macro