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

时间:2009-09-28 13:04:08

标签: 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
{

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

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

有正确的方法吗?

21 个答案:

答案 0 :(得分:282)

你可以put it in "(void)var;" expression(什么都不做),以便编译器看到它被使用。这在编译器之间是可移植的。

E.g。

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);
}

答案 1 :(得分:87)

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

int foo (__attribute__((unused)) int bar) {
   return 0;
}

答案 2 :(得分:35)

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

答案 3 :(得分:34)

C ++ 17现在提供INSERT INTO #t1 (transid,content,userid,dtcreate) SELECT (CONVERT(VARCHAR(10), dtcreate, 112)+RIGHT('0000'+CONVERT(VARCHAR, ( ROW_NUMBER()over(order by (Select 1)))), 5)) , content, userid, dtcreate FROM @t2 属性。

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

相当不错且标准。

答案 4 :(得分:23)

一位同事刚刚把我指向了这个漂亮的小宏here

为方便起见,我将在下面加入宏。

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

答案 5 :(得分:23)

默认情况下,

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

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

答案 6 :(得分:22)

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

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

答案 7 :(得分:19)

C ++ 17更新

在C ++ 17中,我们获得了{strong> [[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);
 }
     

实现不应该警告b是否未使用,无论是否定义了NDEBUG。 - 例子]

对于以下示例:

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

对于 bar unused_bool See it live),clang和gcc都会使用 -Wall -Wextra 生成诊断。< / p>

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

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

see it live

在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

答案 8 :(得分:10)

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

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

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

答案 9 :(得分:7)

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

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

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

答案 10 :(得分:6)

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

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

示例:

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

这可能看起来很神秘,因此定义了像UNUSED这样的宏。 MFC的方式是:

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

像这样你看到调试版本中的警告仍然有用。

答案 11 :(得分:5)

哈哈!我不认为在SO上还有另一个问题能比这个更好地揭示所有被混沌破坏的异端!

在充分尊重C ++ 17的前提下,C++ Core Guidelines中有明确的准则。 AFAIR,早在2009年就可以使用此选项。而且如果有人说这被认为是Doxygen中的错误,那么Doxygen中就有一个错误

答案 12 :(得分: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))

有点不那么难看。

答案 13 :(得分:3)

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

UNREFERENCED PARAMETER(p)定义为

#define UNREFERENCED_PARAMETER(P)          (P)
<\ n>在WinNT.h中。

答案 14 :(得分:2)

您可以使用__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
}

答案 15 :(得分:2)

使用编译器的标志,例如GCC的旗帜: -Wno-unused-variable

答案 16 :(得分:1)

这很有效,但需要 C ++ 11

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

答案 17 :(得分: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; }

答案 18 :(得分:1)

我看到了这种情况,而不是(void)param2来使警告静音:

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

看起来像这样在C ++ 11中添加了

答案 19 :(得分: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

答案 20 :(得分:-13)

我没有看到你的警告问题。在方法/函数头中记录它,编译器xy将在此处发出(正确)警告,但平台z需要这些变量。

警告是正确的,无需将其关闭。它不会使程序无效 - 但应该记录,这是有原因的。