Вариативная неиспользуемые функции/макроса
известный и портативный способ подавления предупреждений компилятора C о неиспользуемых переменных (см. неиспользуемые предупреждения параметров в коде C):
#define UNUSED(x) (void)(x)
Я ищу способ обобщить это, чтобы взять несколько входов (разного типа):
void foo(int a, long b, void* c){
/* Want this: */
ALL_UNUSED(a, b, c);
/* instead of: */
UNUSED(a);
UNUSED(b);
UNUSED(c);
}
один из способов, который, кажется, сделать трюк, чтобы использовать функции с переменным числом аргументов
static inline void ALL_UNUSED(int dummy, ...) {}
тем не менее, я подозреваю, что это решение нежелательно для экспертного глаза.
есть соответствует стандарту и портативный (т. е. не используя __attribute__((unused))
) способ сделать вариативным неиспользованный() функция/макрос? Большое спасибо!
редактировать
кажется, не существует чистого способа сделать то, что я просил в контексте C99 или препроцессора C. Такова жизнь.
в своем ответе ниже @Dabo показывает довольно интересный способ сделать то, что я просил, используя серию макросов. Это аккуратно и информативно (по крайней мере для меня), поэтому я принимаю это ответ. Тем не менее, я бы не стал развертывать его в большом проекте, потому что он достаточно слезлив, чтобы перевесить пользу, которую он приносит (в моих глазах). Но здесь люди придут к разным выводам.
как отмечено ниже, подход к использованию пустой вариационной функции также не идеален. Хотя это довольно элегантный однострочный, он будет провоцировать предупреждения о unititialized переменных (если они есть). Кроме того, вы должны доверять своему компилятору, чтобы полностью оптимизировать его, что я возражаю в принцип, но все компиляторы, с которыми я пробовал, действительно делают.
один уместный случай когда stubbing функции после предыдущего высокопоставленного участка конструкции интерфейса. Тогда ваши неиспользуемые переменные будут аргументами функции и инициализированы по определению, и следующий подход отлично работает
static inline void UNUSED(int dummy, ...) {}
void foo(int a, long b, void* c){
UNUSED(a, b, b); /* No warnings */
}
4 ответов
на основе этих двух сообщений Variadic макрос для подсчета количества аргументов и перегрузка макросов я сделал следующее
#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__ )
что можно использовать следующим образом
int main()
{
int a,b,c;
long f,d;
ALL_UNUSED(a,b,c,f,d);
return 0;
}
расширение макроса eclipse дает:
(void)(a),(void)(b),(void)(c),(void)(f),(void)(d)
составлен с gcc -Wall
без предупреждений
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
как inline
метод, который вы выложили, быстрый тест
int a=0;
long f,d;
ALL_UNUSEDINLINE(a,f,&d);
дает ‘f’ is used uninitialized in this function [-Wuninitialized]
предупреждение. Так вот хотя бы один прецедент, который нарушает общность этого aproach
что вы думаете об этом:
#define UNUSED(...) [__VA_ARGS__](){};
пример:
void f(int a, char* b, long d)
{
UNUSED(a, b, d);
}
должно быть расширено объявление определение лямбда:
[a,b,d](){}; //optimized by compiler (I hope!)
=== = = = испытано с http://gcc.godbolt.org ===== Я попробовал этот код:
#define UNUSED(...) [__VA_ARGS__](){};
int square(int num, float a) {
UNUSED(a);
return num * num;
}
результирующий вывод (скомпилированный с-O0-Wall):
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:
если вы можете использовать C++11, это может быть лучшим решением :
template <typename ...Args>
void UNUSED(Args&& ...args)
{
(void)(sizeof...(args));
}
Я взял Дабо (https://stackoverflow.com/a/23238813/5126486) удивительное решение и улучшено немного, поэтому его легче расширить до более чем 5:
#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 UNUSED6(a,b,c,d,e,f) (void)(a),UNUSED5(b,c,d,e,f)
#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__ )
вы можете использовать время компиляции __VA_ARGS__
макрос.
#define UNUSED(...) (void)(__VA_ARGS__)
обновление: после многих испытаний я подошел к оптимизированному решению:
#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;
}
Примечания:
это не устраняет предупреждения полностью, но уменьшается они
3
тот же тип предупреждений:warning: value computed is not used
первый и последний
x
обеспечить назначение того же тип данных.Я скажу, что он оптимизирован, потому что для любого количества неиспользуемых переменных он дает
3
предупреждения (я могу ошибаться, пожалуйста, проверьте его самостоятельно и сообщите мне, если вы получите больше), а количество кода (макро-манипуляции), необходимое для его достижения, меньше.Я все еще работаю над этим, опубликую, если я достигну лучшего решения.