我如何最好地沉默关于未使用变量的警告?

我有一个跨平台的应用程序,在我的几个函数中,并不是所有传递给函数的值都被利用。因此我从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
{

这是如此丑陋,但似乎是编译器更喜欢的方式。

还是把函数末尾的变量赋值为0 ?(我讨厌这样做,因为它改变了程序流中的某些东西,从而使编译器警告静音)。

有正确的方法吗?

280339 次浏览

你可以把它放在"(void)var;"表达式中(不做任何事),这样编译器就可以看到它被使用了。这在编译器之间是可移植的。

如。

void foo(int param1, int param2)
{
(void)param2;
bar(param1);
}

或者,

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


void foo(int param1, int param2)
{
UNUSED(param2);
bar(param1);
}

总是注释掉参数名是否不安全?如果不是,你可以做一些

#ifdef _MSC_VER
# define P_(n) n
#else
# define P_(n)
#endif


void ProcessOps::sendToExternalApp(
QString sAppName, QString sImagePath,
qreal P_(qrLeft), qreal P_(qrTop), qreal P_(qrWidth), qreal P_(qrHeight))

它没有有点那么丑。

我看不出你对警告有什么意见。在方法/函数头文件中记录编译器xy将在这里发出(正确的)警告,但是平台z需要这些变量。

警告是正确的,不需要关闭。它不会使程序失效——但它应该被记录下来,这是有原因的。

当前的解决方案是最好的——如果不使用参数名,就注释掉它。这适用于所有编译器,因此不需要使用预处理程序专门为GCC做这件事。

大多数时候,使用预处理器指令被认为是邪恶的。理想情况下,你应该像避开害虫一样避开它们。记住,让编译器理解你的代码很容易,让其他程序员理解你的代码就难多了。到处都有几十个这样的案例,这让你以后很难阅读,也让别人现在很难阅读。

一种方法可能是将参数放在某种类型的参数类中。然后,您可以只使用变量的一个子集(实际上相当于为0赋值),或者为每个平台对该参数类有不同的专门化。然而,这可能并不值得,你需要分析它是否合适。

如果你能阅读不可能的模板,你可能会在“例外c++”一书中找到高级技巧。如果阅读您代码的人能够掌握书中所教的疯狂内容,那么您将拥有易于阅读的漂亮代码。编译器也会很清楚你在做什么(而不是通过预处理隐藏所有内容)

在GCC和Clang中,你可以使用__attribute__((unused))预处理器指令来实现你的目标 例如:< / p >
int foo (__attribute__((unused)) int bar) {
return 0;
}

使用UNREFERENCED_PARAMETER(p)可以工作。我知道它是在Windows系统的WinNT.h中定义的,也可以很容易地为gcc定义(如果它还没有)。

UNREFERENCED PARAMETER(p)被定义为

#define UNREFERENCED_PARAMETER(P)          (P)

在WinNT.h。

首先,警告是由源文件中的变量定义生成的,而不是头文件。头文件可以保持原始状态,而且应该保持原始状态,因为您可能正在使用类似doxygen的东西来生成api文档。

我假设您在源文件中有完全不同的实现。在这些情况下,您可以注释掉有问题的参数,或者直接写入参数。

例子:

func(int a, int b)
{
b;
foo(a);
}

这可能看起来很神秘,所以定义了一个像UNUSED这样的宏。MFC的做法是:

#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif

像这样,在调试版本中仍然会看到警告,可能会有帮助。

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

为了方便起见,我将包括下面的宏。

#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))

一种更简洁的方法是只注释掉变量名:

int main(int /* argc */, char const** /* argv */) {
return 0;
}

默认不标记这些警告。此警告必须通过显式地向编译器传递-Wunused-parameter或隐式地传递-Wall -Wextra(或其他一些标志的组合)来打开。

未使用的参数警告可以简单地通过向编译器传递-Wno-unused-parameter来抑制,但请注意,这个禁用标志必须出现在编译器命令行中任何可能的此警告的启用标志之后,这样它才能生效。

c++ 17更新

在c++ 17中,我们获得了[[maybe_unused]]属性,该属性包含在(dcl.attr.unused)

attribute-token maybe_unused表示一个名称或实体可能是故意不使用的。应当 每个属性列表中最多出现一次,且不允许出现属性参数子句。 …< / p >

例子:

 [[maybe_unused]] void f([[maybe_unused]] bool thing1,
[[maybe_unused]] bool thing2) {
[[maybe_unused]] bool b = thing1 && thing2;
assert(b);
}

不管是否定义了NDEBUG,实现都不应该警告b未使用。-end示例]

示例如下:

int foo ( int bar) {
bool unused_bool ;
return 0;
}

clang和gcc都使用- wall -Wextra酒吧unused_bool (现场观看)生成诊断。

在添加[[maybe_unused]]时,将停止诊断:

int foo ([[maybe_unused]] int bar) {
[[maybe_unused]] bool unused_bool ;
return 0;
}

现场观看

在c++ 17

在c++ 11中,可以使用lambda表达式(via Ben Deane)和未使用变量的捕获来形成UNUSED宏的另一种形式:

#define UNUSED(x) [&x]{}()

lambda表达式的直接调用应该被优化掉,给出如下示例:

int foo (int bar) {
UNUSED(bar) ;
return 0;
}

我们可以在godbolt中看到调用被优化了:

foo(int):
xorl    %eax, %eax
ret

你可以使用__unused来告诉编译器这个变量可能不会被使用。

- (void)myMethod:(__unused NSObject *)theObject
{
// there will be no warning about `theObject`, because you wrote `__unused`


__unused int theInt = 0;
// there will be no warning, but you are still able to use `theInt` in the future
}

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

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


int main(int argc, char* argv[])
{
unused(argc, argv);
return 0;
}

使用编译器的标志,例如GCC的标志: -Wno-unused-variable < / p >

这工作得很好,但需要c++ 11

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

c++ 17现在提供了[[maybe_unused]]属性。

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

非常漂亮和标准。

我发现大多数给出的答案只适用于局部未使用的变量,并且会导致未使用的静态全局变量的编译错误。

另一个宏需要抑制未使用的静态全局变量的警告。

template <typename T>
const T* UNUSED_VARIABLE(const T& dummy) {
return &dummy;
}
#define UNUSED_GLOBAL_VARIABLE(x) namespace {\
const auto dummy = UNUSED_VARIABLE(x);\
}


static int a = 0;
UNUSED_GLOBAL_VARIABLE(a);


int main ()
{
int b = 3;
UNUSED_VARIABLE(b);
return 0;
}

这是因为匿名命名空间中的非静态全局变量不会报告任何警告。

c++ 11是必需的

 g++  -Wall -O3  -std=c++11 test.cpp

在c++ 11中,这是我使用的解决方案:

template<typename... Ts> inline void Unreferenced(Ts&&...) {}


int Foo(int bar)
{
Unreferenced(bar);
return 0;
}


int Foo2(int bar1, int bar2)
{
Unreferenced(bar1, bar2);
return 0;
}

验证可移植(至少在现代msvc, clang和gcc上),并且在启用优化时不会产生额外的代码。 在没有优化的情况下,将执行额外的函数调用,并将对参数的引用复制到堆栈中,但不涉及宏

如果额外的代码是一个问题,你可以使用这个声明:

(decltype(Unreferenced(bar1, bar2)))0;

但在这一点上,宏提供了更好的可读性:

#define UNREFERENCED(...) { (decltype(Unreferenced(__VA_ARGS__)))0; }

我已经看到了这个代替(void)param2的方法来消除警告:

void foo(int param1, int param2)
{
std::ignore = param2;
bar(param1);
}

看起来这是c++ 11中添加的

哈哈!我不认为还有其他问题能比这个问题更好地揭示所有被混沌腐化的异教徒!

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

void func(void *aux UNUSED)
{
return;
}

SMTH是这样的,在这种情况下,如果你不使用aux,它就不会警告你