288

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

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

或者我是否在函数末尾为变量分配零?(我讨厌它,因为它正在改变程序流程中的某些内容以使编译器警告静音)。

有正确的方法吗?

4

21 回答 21

384

您可以将它放在 " (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);
}
于 2009-09-28T13:08:42.357 回答
124

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

int foo (__attribute__((unused)) int bar) {
   return 0;
}
于 2009-09-28T13:44:16.390 回答
90

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

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

相当不错和标准。

于 2017-05-22T07:21:46.140 回答
43

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

于 2009-09-28T13:12:30.033 回答
36

C++17 更新

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

属性标记maybe_unused 指示名称或实体可能是有意未使用的。它在每个属性列表中最多出现一次,并且不应出现任何属性参数子句。...

例子:

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

无论是否定义了 NDEBUG,实现都不应警告 b 未使用。—结束示例]

对于以下示例:

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

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

在添加[[maybe_unused]]时使诊断静音:

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

现场观看

C++17 之前

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

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

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

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

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

foo(int):
xorl    %eax, %eax
ret
于 2015-07-27T13:44:01.573 回答
29

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

int main(int /* argc */, char const** /* argv */) {
  return 0;
}
于 2013-10-10T07:35:47.470 回答
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))
于 2009-11-03T20:55:55.583 回答
24

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

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

于 2013-10-17T16:10:41.870 回答
15

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

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

int main(int argc, char* argv[])
{
    unused(argc, argv);
    return 0;
}
于 2017-01-13T14:07:01.350 回答
8

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

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

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

于 2009-09-28T13:17:28.550 回答
8

Lol! I dont think there is another question on SO that reveal all the heretics corrupted by Chaos better that this one!

With all due respect to C++17 there is a clear guideline in C++ Core Guidelines. AFAIR, back in 2009 this option was available as well as today. And if somebody says it is considered as a bug in Doxygen then there is a bug in Doxygen

于 2020-06-15T12:23:04.640 回答
7

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

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

例子:

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

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

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

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

于 2009-09-28T14:27:34.657 回答
7

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

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

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

于 2019-10-04T22:26:31.520 回答
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))

它不那么丑陋了。

于 2009-09-28T13:11:10.133 回答
4

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

UNREFERENCED PARAMETER(p)定义为

#define UNREFERENCED_PARAMETER(P)          (P)

在 WinNT.h 中。

于 2009-09-28T14:17:40.753 回答
2

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

于 2017-03-03T18:11:54.393 回答
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; }
于 2018-07-02T16:54:18.437 回答
1

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

template <typename ...Args>
void unused(Args&& ...args)
{
  (void)(sizeof...(args));
}
于 2017-03-19T17:13:44.650 回答
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
于 2017-09-25T02:34:09.690 回答
0

您可以使用__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
}
于 2016-02-10T23:56:43.613 回答
-14

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

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

于 2009-09-28T13:11:35.043 回答