问题 Variadic 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展示了一种非常有趣的方式来做我要求使用的一系列宏。这是整洁和翔实的(至少对我而言),所以我接受了这个答案。也就是说,我不会将它部署在一个大型项目中,因为它的篇幅足以超过它带来的好处(在我看来)。但人们会在这里得出不同的结论。

如下所述,使用空可变参数函数的方法也不完美。虽然它是一个非常优雅的单行,但它会引发关于单元化变量的警告(如果它们是)。此外,你必须相信你的编译器完全优化它,我原则上反对,但我尝试过的所有编译器实际上都是这样做的。

一个相关的情况是在早期高级接口设计阶段之后存根功能。然后你未使用的变量都将是函数参数并按定义初始化,以下方法可以正常工作

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

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

6174
2018-04-23 05:56


起源

怎么样使用 #define UNUSED(...) (void)(__VA_ARGS__)。 - Don't You Worry Child
可悲的是没有 - 尝试过。编译器将警告未使用的表达式结果或“value as statement”。在语义上,你期望什么(void)(a,b,c);是什么意思? - dag
感谢您指出了这一点。尝试其他方式...... - Don't You Worry Child
任何人都可以详细说明可变功能的问题吗? - Don't You Worry Child
注意gcc有选项 -Wno-unused-variable 这似乎做你要求的?虽然问题可能更多是关于varadics的宏... - spinkus


答案:


基于这两个帖子 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 没有警告

编辑:

#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] 警告。所以这里至少有一个用例打破了这种方法的普遍性


9
2018-04-23 08:27



相当不错!我会玩这个,看看它的感觉。手动枚举似乎是不可避免的,但几乎没有人会爱上cpp。谢谢! - dag
我可以问一下你对帖子中提到的void variadic function方法有什么看法(比你令人印象深刻的宏解决方案稍短)?它是否会使您不正确和/或有缺陷? - dag
@dag看到我的edit2关于 inline,我认为它回答了你的问题。 - Dabo
感谢您指出了这一点!我想到的(未说明的)用例实际上只是为了抑制未使用的函数参数的警告。 - dag
非常有用,谢谢! - hesham_EE


你怎么看待这件事:

#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

编辑:

如果你可以使用C ++ 11,这可能是一个更好的解决方案:

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

4
2017-09-21 06:56



这个问题是关于C,而不是C ++ 11。
导致“警告:表达结果未使用”,但这可能很容易修复 - Simon Warta


我带了Dabo的(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__ )

2
2017-07-17 07:22





您可以使用编译时间 __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;
}

笔记: 

  1. 它并没有完全消除警告 减少 他们只是 3 相同类型的警告:
    warning: value computed is not used

  2. 第一个也是最后一个 x 确保分配相同的数据类型。

  3. 我会说它是优化的,因为它给出了任意数量的未使用变量 3 警告(我可能错了,请自己测试一下,如果你得到更多就报告我),实现它所需的代码量(MACRO操作)就越少。

  4. 我还在努力,如果我找到更好的解决方案,我会发布。


-1
2018-04-23 06:01



谢谢@MadHatter,但我认为Clang和GCC仍然会发出警告。 GCC“警告:逗号表达式的左侧操作数无效[-Wunused-value]”,Clang:“警告:表达式结果未使用[-Wunused-value]” - dag
雅!我自己编译了 gcc -Wall 并得到同样的警告。仍在尝试...... - Don't You Worry Child