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

319

我有一个跨平台应用程序,在一些函数中并没有使用传递给函数的所有值。因此,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
{

这看起来很丑陋,但似乎是编译器喜欢的方式。

或者我在函数末尾将变量赋值为零?(我讨厌这种方法,因为它会改变程序流以消除编译器警告)。

有没有正确的方式?


7
我刚意识到你去年11月曾提出过类似的问题,所以这就是为什么它看起来很熟悉! ;) https://dev59.com/5XVC5IYBdhLWcg3wZwJT#308286 - Alex B
9
为什么不在两个编译器中都将它们注释掉?如果一个参数在一个编译器上未被使用,那么可能在另一个编译器上也未被使用... - Roger Lipscombe
12
你应该知道Qt有一个Q_UNUSED宏专门用于这个。在文档中查看它。 - Evan Teran
1
C语言的解决方案在C++中也可以正常工作:https://dev59.com/EXA65IYBdhLWcg3w2iip#3599170 - JonnyJD
如果您可以使用特定于编译器的构建标志,那么“-Wno-unused-parameter”也可能是一种选择。 - Code Abominator
核心指南 F9: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-unused - GrendleM
23个回答

10

我看到过这种用法来消除警告,它代替了 (void)param2 的写法:

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

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


编译后似乎在做某些事情,而非被忽略。 - ghchoi

9

大多数情况下,使用预处理指令被认为是不好的。理想情况下,您应该像避开害虫一样避免它们。记住,让编译器理解您的代码很容易,让其他程序员理解您的代码则更难。这里或那里有几十个这样的案例会使自己以后或现在的其他人阅读变得非常困难。

一种方法可能是将参数组合成某种参数类。然后,您可以仅使用变量的子集(相当于将其分配为0),或者为每个平台具有不同的参数类专业化。但是,这可能不值得,您需要分析它是否适合。

如果您能够阅读不可能的模板,您可能会在“ Exceptional C ++”书中找到高级提示。如果那些阅读您代码的人可以掌握该书中教授的疯狂技巧,则您将拥有美丽且易于阅读的代码。编译器也将清楚地了解您正在做什么(而不是通过预处理隐藏一切)


8
“在大多数情况下,使用预处理器指令被认为是一种不良习惯。” 真的吗?由谁认为? - Graeme Perrow
15
对于任何关心作用域、能够正确调试或保持心理健康的人来说。 - Bill
3
@Graeme,当我们只看到它的4行时,它看起来很无害,但是如果在其周围散布,它会引起头痛。 #ifdef基本上允许您放置多个版本的源代码,而编译器只会看到其中一个版本。正如Bill所提到的,这也使得调试变得更加困难。我已经阅读了各种书籍和博客中有关预处理指令邪恶性的内容,并且我自己也有过相关经验。当然,一切都是相对的。有时预处理指令很有意义,因为其他任何选择都会带来更严重的后果,我的观点仅在于应该尽可能避免使用它。 - Ben Dadsetan
2
过度使用不好,但我认为 #define UNUSED(expr) (void)(expr) 是适当的。 - JonnyJD

7

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

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

例如:

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

这可能看起来很晦涩,所以可以定义一个类似UNUSED的宏。MFC的做法是这样的:
#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif

就像这样,您可以在调试构建中看到警告,这可能会有所帮助。


4

总是注释掉参数名称不安全吗?如果不是,你可以这样做

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

这看起来稍微好看一些。


4
在C++中,函数参数名称并非强制性的,而在C中则是强制性的。这只是为了提供一种标准且方便的方式来避免警告。请注意,此处不进行解释。 - AProgrammer
1
@hacker,我从来没有这么说过。我倾向于指出C和C++之间的区别,特别是当它们在你认为是共同子集的区域时...这只是一种习惯,因为我正在处理混合代码库。 - AProgrammer

4

使用UNREFERENCED_PARAMETER(p)可能有效。我知道它在Windows系统中已在WinNT.h中定义,并且可以轻松地为gcc定义(如果还未定义)。

UNREFERENCED PARAMETER(p)被定义为:

#define UNREFERENCED_PARAMETER(P)          (P)

在WinNT.h中。


那么,使用该参数来隐藏关于它未被使用的警告? - user4945014

4

使用编译器标志(compiler's flag),例如针对GCC的标志:-Wno-unused-variable


1
在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; }

1

这个很好用,但需要C++11

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

1
这需要C++14才能实现,而在C++11中无法工作?我看不出来。此外,除了宏之外,使用ALLCAPS是不被鼓励的,因为这会使它们看起来丑陋和不受欢迎,但实际上并没有什么不好的地方,只是使用static_cast会更好一些。 - underscore_d

0

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

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

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

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

类似这样,在这种情况下,如果您不使用辅助程序,它将不会发出警告。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接