Вариадическая UNUSED-функция/макрос - программирование
Подтвердить что ты не робот

Вариадическая UNUSED-функция/макрос

Известный и переносимый способ подавить предупреждения компилятора 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))) способ сделать вариационную UNUSED() функцию/макрос? Большое спасибо!

ИЗМЕНИТЬ

Кажется, что нет чистого способа делать то, что я просил, в контексте C99 или препроцессора C. Такова жизнь.

В своем ответе ниже @Dabo показывает довольно интересный способ сделать то, что я попросил использовать ряд макросов. Это аккуратно и информативно (по крайней мере, для меня), поэтому я принимаю этот ответ. Тем не менее, я бы не разворачивал его в большом проекте, потому что он достаточно силен, чтобы перевешивать пользу, которую он приносит (в моих глазах). Но здесь люди придут к разным выводам.

Как отмечено ниже, подход использования пустой вариационной функции также не идеален. Хотя это довольно элегантный однострочный, он будет вызывать предупреждения об элементарных переменных (если они есть). Кроме того, вы должны доверять своему компилятору, чтобы полностью его оптимизировать, на что я возражаю в принципе, но что все компиляторы, с которыми я пытался это сделать, действительно делают.

Одним из релевантных случаев является выполнение функций stubbing после этапа разработки интерфейса на высоком уровне. Тогда ваши неиспользуемые переменные будут функциональными аргументами и инициализированы по определению, и следующий подход работает отлично

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

void foo(int a, long b, void* c){
    UNUSED(a, b, b); /* No warnings */
}
4b9b3361

Ответ 1

На основе этих двух сообщений Variadic macro для подсчета количества аргументов и Перегрузка макросов я сделал следующее

#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

Ответ 2

Что вы думаете об этом:

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

Пример:

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

Должно быть расширено объявление lambdas:

[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:

Если вы можете использовать С++ 11, это может быть лучшим решением:

template <typename ...Args>
void UNUSED(Args&& ...args)
{
    (void)(sizeof...(args));
}

Ответ 3

Я взял Dabo (fooobar.com/questions/546847/...) удивительное решение и немного улучшил его, чтобы было проще продлить до более 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__ )

Ответ 4

Вы можете использовать макрос .

#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 (возможно, я ошибаюсь, пожалуйста, проверьте его самостоятельно и сообщите мне, если вы получите больше) и количество кода ( MACRO), необходимых для его достижения, меньше.

  • Я все еще работаю над этим, опубликую, если дойду до лучшего решения.