提问人:Phil Hannent 提问时间:9/28/2009 最后编辑:Jim FellPhil Hannent 更新时间:8/17/2023 访问量:317138
如何最好地将有关未使用变量的警告静音?
How do I best silence a warning about unused variables?
问:
我有一个跨平台的应用程序,在我的一些函数中,并非所有传递给函数的值都被利用。因此,我收到来自 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
{
这太丑陋了,但似乎是编译器喜欢的方式。
还是将函数末尾的变量赋值为零?(我讨厌它,因为它正在改变程序流程中的某些内容以使编译器警告静音)。
有正确的方法吗?
答:
你可以把它放在 “(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);
}
评论
Q_UNUSED
#define UNUSED(expr) (void)(expr)
template<typename... Args> void f(const Args&... args)
(void)args;
(void)args...;
总是注释掉参数名称不安全吗?如果不是,你可以做类似的事情
#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 执行此操作。
评论
g++
大多数时候,使用预处理器指令被认为是邪恶的。理想情况下,您希望像害虫一样避免它们。请记住,让编译器理解你的代码很容易,让其他程序员理解你的代码要困难得多。像这样的案例在这里和那里有几十个,使你以后或现在很难为自己或其他人阅读。
一种方法可能是将参数组合到某种参数类中。然后,您可以只使用变量的子集(实际上相当于分配 0),或者为每个平台使用该参数类的不同专用化。然而,这可能不值得,您需要分析它是否合适。
如果你能阅读不可能的模板,你可能会在“Exceptional C++”一书中找到高级提示。如果阅读你的代码的人能够掌握他们的技能,涵盖那本书中教授的疯狂内容,那么你就会拥有漂亮的代码,也可以很容易地阅读。编译器也会很清楚你在做什么(而不是通过预处理来隐藏所有内容)
评论
#define UNUSED(expr) (void)(expr)
在 GCC 和 Clang 中,您可以使用预处理器指令来实现您的目标。
例如:__attribute__((unused))
int foo (__attribute__((unused)) int bar) {
return 0;
}
评论
MSVC
使用一个可以工作。我知道它是在 Windows 系统的 WinNT.h 中定义的,也可以轻松地为 gcc 定义(如果它还没有的话)。UNREFERENCED_PARAMETER(p)
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;
}
评论
#if 0 / #endif
默认情况下,GCC 不会标记这些警告。此警告必须通过传递给编译器来显式打开,或者通过传递(或可能的其他标志组合)隐式打开。-Wunused-parameter
-Wall -Wextra
未使用的参数警告可以通过传递给编译器来简单地禁止显示,但请注意,此禁用标志必须出现在编译器命令行中此警告的任何可能的启用标志之后,以便它生效。-Wno-unused-parameter
评论
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 -Wextra 为 bar 和 unused_bool 生成诊断(实时查看)。
添加 [[maybe_unused]] 会使诊断静音:
int foo ([[maybe_unused]] int bar) {
[[maybe_unused]] bool unused_bool ;
return 0;
}
现场观看。
C++17 之前
在 C++11 中,可以使用 lambda 表达式(通过 Ben Deane)来捕获未使用的变量来形成宏的另一种形式:UNUSED
#define UNUSED(x) [&x]{}()
鉴于以下示例,应优化 lambda 表达式的直接调用:
int foo (int bar) {
UNUSED(bar) ;
return 0;
}
我们可以在 Godbolt 中看到,调用被优化了:
foo(int):
xorl %eax, %eax
ret
评论
template <class T> inline void NOTUSED( T const & result ) { static_cast<void>(result); }
[&x]{}()
实际上不会使警告静音,而是将警告从调用方函数传递到 lambda。编译器需要一段时间才能将其识别为警告,但 clang-tidy 已经抱怨捕获列表中未使用的变量。
您可以使用它来告诉编译器变量可能未被使用。__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
}
评论
__unused
__
将一个或多个参数声明为未使用的无宏和可移植方法:
template <typename... Args> inline void unused(Args&&...) {}
int main(int argc, char* argv[])
{
unused(argc, argv);
return 0;
}
评论
使用编译器的标志,例如 GCC 的标志:-Wno-unused-variable
这效果很好,但需要 C++11
template <typename ...Args>
void unused(Args&& ...args)
{
(void)(sizeof...(args));
}
评论
ALLCAPS
static_cast
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 中添加的
评论
哈哈!我不认为 SO 上还有另一个问题比这个问题更能揭示所有被混沌腐蚀的异教徒!
在充分尊重C++17的情况下,C++核心准则中有一个明确的指导方针。AFAIR,早在 2009 年,此选项就和今天一样可用。如果有人说它被认为是 Doxygen 中的错误,那么 Doxygen 中就存在一个错误
评论
void func(void *aux UNUSED)
{
return;
}
像这样,在这种情况下,如果你不使用辅助,它不会警告你
为未使用的局部变量定义宏:
#define UNUSED(x) (void)((x))
评论
Q_UNUSED