如何最好地消除有关未使用变量的警告?

Phi*_*ent 212 c++ gcc warnings gcc-warning

我有一个跨平台应用程序,在我的一些函数中,并没有使用传递给函数的所有值.因此我收到GCC的警告,告诉我有未使用的变量.

编码警告的最佳编码方式是什么?

围绕这个功能的#ifdef?

#ifdef _MSC_VER
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal qrLeft, qreal qrTop, qreal qrWidth, qreal qrHeight)
#else
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal /*qrLeft*/, qreal /*qrTop*/, qreal /*qrWidth*/, qreal /*qrHeight*/)
#endif
{
Run Code Online (Sandbox Code Playgroud)

这太丑了,但似乎是编译器喜欢的方式.

或者我在函数末尾为变量赋值为零?(我讨厌它,因为它改变了程序流程中的某些东西以使编译器警告静音).

有正确的方法吗?

Ale*_*x B 296

你可以将它放在" (void)var;"表达式中(什么都不做),以便编译器看到它被使用.这在编译器之间是可移植的.

例如

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}
Run Code Online (Sandbox Code Playgroud)

要么,

#define UNUSED(expr) do { (void)(expr); } while (0)
...

void foo(int param1, int param2)
{
    UNUSED(param2);
    bar(param1);
}
Run Code Online (Sandbox Code Playgroud)

  • +1 - 仍然我会记录为什么你不使用变量,即使它在那里. (19认同)
  • 这就是原则上实施`Q_UNUSED`的方式. (16认同)
  • 只是`#define UNUSED(expr)(void)(expr)`也应该工作(没有do-while). (12认同)
  • @Cameron你可以简单地在C++中省略参数名称.如果它是模板化的,它将不会在C中使用,因此您不需要演员到虚空的技巧. (10认同)
  • 我想知道如何为可变参数模板做到这一点.在`template <typename ... Args> void f(const Args&... args)`我不能写`(void)args;`或`(void)args ...;`因为两者都是语法错误. (6认同)
  • @MarkKCowan 或者只是 `((void)args, ...)`。 (3认同)
  • 警告:在优化构建中,void 转换通常会被优化掉,但仍然会导致未使用的变量错误。 (2认同)
  • 如果将对不完整类型的引用转换为void,则MSVC 2013将失败并显示未定义的类型错误.例如`struct Foo; void bar(Foo&foo){(void)foo; }导致错误"使用未定义类型Foo".解决方法是在转换之前获取foo的地址:`(void)&foo`.所以`#define UNUSED(arg)((void)&(arg))`是最便携的,虽然很难看. (2认同)

ezp*_*zpz 93

在GCC和Clang中,您可以使用__attribute__((unused))预处理器指令来实现您的目标.
例如:

int foo (__attribute__((unused)) int bar) {
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是回调函数的最佳解决方案。 (4认同)
  • 遗憾的是,这无法使用“MSVC”等进行编译,因此它不是一个好的可移植解决方案。 (3认同)
  • clang 也支持:https://clang.llvm.org/docs/AttributeReference.html#maybe-unused-unused-gnu-unused (2认同)
  • @SonicAtom 不,因为它不可移植。 (2认同)

ale*_*gle 38

您当前的解决方案是最好的 - 如果您不使用它,请注释掉参数名称.这适用于所有编译器,因此您不必使用预处理器专门为GCC执行此操作.

  • 只是为了强化这个答案 - 你不需要#ifdef,只需注释掉未使用的参数名称. (7认同)
  • 我有一个案例,其中参数是回调的一部分,并注释它打破了编译(所以我不知道为什么`g ++`警告它.)在这种情况下,你会推荐什么? (4认同)

scx*_*scx 37

C++ 17现在提供了该[[maybe_unused]]属性.

http://en.cppreference.com/w/cpp/language/attributes

非常好,标准.


小智 24

一位同事在这里向我指出了这个漂亮的小宏

为方便起见,我将在下面添加宏.

#ifdef UNUSED
#elif defined(__GNUC__) 
# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) 
#elif defined(__LCLINT__) 
# define UNUSED(x) /*@unused@*/ x 
#else 
# define UNUSED(x) x 
#endif

void dcc_mon_siginfo_handler(int UNUSED(whatsig))
Run Code Online (Sandbox Code Playgroud)

  • "nice""macro""c ++" - 选择2. (9认同)

Dig*_*uma 23

默认情况下,不会标记这些警告.必须通过传递-Wunused-parameter给编译器或通过传递-Wall -Wextra(或可能是其他一些标志组合)隐式地打开此警告.

可以通过传递-Wno-unused-parameter给编译器来简单地抑制未使用的参数警告,但请注意,此禁用标志必须位于编译器命令行中此警告的任何可能的启用标志之后,以使其生效.

  • 尽管如此,这可能不是问题的最佳答案(因为问题是如何避免警告,而不是如何禁用它),这个答案可能是来自谷歌(像我一样)的人正在搜索("如何禁用此警告").所以我给+1,谢谢你的回答! (2认同)

Mar*_*ski 22

更简洁的方法就是注释掉变量名称:

int main(int /* argc */, char const** /* argv */) {
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • @AlexisWilke:这将成为doxygen中的一个错误,IMO (16认同)
  • 如果你有doxygen并想要记录参数,那就不好了. (8认同)
  • 您可以在#ifdef DOXYGEN上有条件地#define YOUR_PROJECT_UNUSED(argname),以便doxygen可以通过int main(int YOUR_PROJECT_UNUSED(argc),...)查看名称而真正的编译器没有.不是很棒,但确实有用. (3认同)

Sha*_*our 22

C++ 17更新

在C++ 17中,我们获得了[[maybe_unused]]属性,[dcl.attr.unused]

属性标记maybe_unused指示可能故意不使用名称或实体.它应该在每个属性列表中最多出现一次,并且不存在attribute-argument-clause....

例:

 [[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2) {
  [[maybe_unused]] bool b = thing1 && thing2;
    assert(b);
 }
Run Code Online (Sandbox Code Playgroud)

无论是否定义了NDEBUG,实现都不应警告b未使用. - 末端的例子]

对于以下示例:

int foo ( int bar) {
    bool unused_bool ;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

clang和gcc都使用-Wall -Wextrabarunused_bool生成诊断(实时查看).

添加[[maybe_unused]]会使诊断静音:

int foo ([[maybe_unused]] int bar) {
    [[maybe_unused]] bool unused_bool ;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

看到它.

在C++之前17

在C++ 11中,UNUSED可以使用lambda表达式(通过Ben Deane)形成宏的替代形式,捕获未使用的变量:

#define UNUSED(x) [&x]{}()
Run Code Online (Sandbox Code Playgroud)

应该优化对lambda表达式的立即调用,给出以下示例:

int foo (int bar) {
    UNUSED(bar) ;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我们可以在godbolt中看到呼叫被优化掉了:

foo(int):
xorl    %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)

  • 所以你提到C++ 11然后设法呈现一个宏?!哎哟! 也许使用一个功能会更干净?`template <class T> inline void NOTUSED(T const&result){static_cast <void>(result); 我想你也可以在函数中使用lambda. (5认同)
  • `[&x] {}()`并没有真正使警告静音,而是将警告从调用函数传递给lambda.编译器将此识别为警告需要一段时间,但是已经抱怨已经抱怨捕获列表中未使用的变量. (4认同)

Phi*_*ppe 12

无宏且可移植的方式将一个或多个参数声明为未使用:

template <typename... Args> inline void unused(Args&&...) {}

int main(int argc, char* argv[])
{
    unused(argc, argv);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*tan 8

使用预处理程序指令在大多数情况下都被认为是邪恶的.理想情况下,你想像害虫一样避免它们.请记住,让编译器理解您的代码很容易,允许其他程序员理解您的代码要困难得多.像这样的几十个案例使得以后或其他人现在很难自己阅读.

一种方法可能是将您的参数放在某种参数类中.然后,您可以仅使用变量的子集(相当于您真正分配0)或者为每个平台使用该参数类的不同特化.然而,这可能不值得,你需要分析它是否合适.

如果您可以阅读不可能的模板,您可能会在"Exceptional C++"一书中找到高级技巧.如果能够阅读你的代码的人能够将他们的技能集包含在该书中教授的疯狂内容中,那么你将拥有可以轻松阅读的漂亮代码.编译器也会很清楚你在做什么(而不是通过预处理隐藏所有内容)

  • 任何关心范围,能够正确调试或理智的人. (12认同)
  • "在大多数情况下,使用预处理程序指令被认为是邪恶的." 真?由谁? (5认同)
  • @Graeme,当我们只看到它的4行时它看起来很无辜,但它周围的传播确实会引起头痛.#ifdef基本上允许您放置源代码的多个版本,编译器只会看到一个.比尔提到,这也使得调试变得更加困难.我已经阅读过各种书籍和博客中的预处理器指令的邪恶,以及自己经历过的.当然,一切都是相对的.有时预处理器指令只是有意义,因为其他任何东西都会产生更糟糕的后果,我的观点仅在于它应尽可能避免. (2认同)
  • 过度使用是不好的,但我认为“#define UNUSED(expr) (void)(expr)”是合适的。 (2认同)

rio*_*oki 7

首先,警告是由源文件中的变量定义而不是头文件生成的.标题可以保持原始状态,因为您可能正在使用doxygen之类的东西来生成API文档.

我将假设您在源文件中具有完全不同的实现.在这些情况下,您可以注释掉有问题的参数或只写参数.

例:

func(int a, int b)
{
    b;
    foo(a);
}
Run Code Online (Sandbox Code Playgroud)

这可能看起来很神秘,因此定义了像UNUSED这样的宏.MFC的做法是:

#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif
Run Code Online (Sandbox Code Playgroud)

像这样你看到仍然在调试版本中的警告可能会有所帮助.


kru*_*pan 6

我已经看到了这一点,而不是(void)param2消除警告的方式:

void foo(int param1, int param2)
{
    std::ignore = param2;
    bar(param1);
}
Run Code Online (Sandbox Code Playgroud)

看起来这是在 C++11 中添加的


kre*_*ieg 6

哈哈!我不认为关于 SO 的另一个问题可以比这个问题更好地揭示所有被混沌腐蚀的异端!

出于对 C++17 的尊重,C++ 核心指南中有明确的指南。AFAIR,早在 2009 年,这个选项就和今天一样可用。如果有人说它被认为是 Doxygen 中的一个错误,那么 Doxygen 中就有一个错误

  • 多么典型啊!投票数最低的最佳答案...(捂脸) (3认同)