我有一个跨平台的应用程序,在我的几个函数中,并不是所有传递给函数的值都被利用。因此我从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 ?(我讨厌这样做,因为它改变了程序流中的某些东西,从而使编译器警告静音)。
有正确的方法吗?
首先,警告是由源文件中的变量定义生成的,而不是头文件。头文件可以保持原始状态,而且应该保持原始状态,因为您可能正在使用类似doxygen的东西来生成api文档。
我假设您在源文件中有完全不同的实现。在这些情况下,您可以注释掉有问题的参数,或者直接写入参数。
例子:
func(int a, int b)
{
b;
foo(a);
}
这可能看起来很神秘,所以定义了一个像UNUSED这样的宏。MFC的做法是:
#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif
像这样,在调试版本中仍然会看到警告,可能会有帮助。
c++ 17更新
在c++ 17中,我们获得了[[maybe_unused]]属性,该属性包含在[dcl.attr.unused]中。
属性令牌maybe_unused表示一个名称或实体可能是故意未使用的。应当
每个属性列表中最多出现一次,且不允许出现属性参数子句。
...
例子:
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
[[maybe_unused]] bool thing2 {
[[maybe_unused]] bool b = thing1 && thing2;
断言(b);
}
不管是否定义了NDEBUG,实现都不应该警告b未使用。-end示例]
示例如下:
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 <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; }