如果我们编译以下代码:

#include <stdio.h>
int main(int argc, char** argv)
 {
     int n;
     int nRet = printf("Hello, world!");
     return 0;    
 }



编译器一般会发出以下警告(VS2015):

1>f:\mycode\cpptest\main.cpp(55): warning C4100: “argv”: 未引用的形参
1>f:\mycode\cpptest\main.cpp(55): warning C4100: “argc”: 未引用的形参
1>f:\mycode\cpptest\main.cpp(67): warning C4101: “a”: 未引用的局部变量
1>f:\mycode\cpptest\main.cpp(68): warning C4189: “nRet”: 局部变量已初始化但不引用

编译器认为,既然我们已经声明/定义了某变量,那我们就有使用它的意图。所以当它检测到我们未对此变量进行实际的使用时,就会发出警告,提醒我们检查代码是否存在错误。

为了代码编译时输出窗口的整洁(以使有价值的提示信息更醒目),我们通常会消除掉此类警告(当然是在我们确认这是有意为之之后)。而在消除此类警告时,隐式地,我们一般有以下四种期望:

编译器不再发出此警告;
不会引起代码逻辑变化;
不会造成性能损失;
不会对代码维护造成负担,包括阅读和修改;
以下提供两种经典解决方案,并分析网上流传的一些方法为什么不可取。

一、宏UNREFERENCED_PARAMETER

Windows开发人员使用宏定义方案。在Windows平台下,可以在<winnt.h>中找到以下宏定义:

#define UNREFERENCED_PARAMETER(P)          (P)

使用方法如下:

int main(int argc, char** argv)
 {
     UNREFERENCED_PARAMETER(argc); // 手动醒目
     UNREFERENCED_PARAMETER(argv); // 手动醒目    int n;
     UNREFERENCED_PARAMETER(n); // 手动醒目
     int nRet = printf("Hello, world!");
     UNREFERENCED_PARAMETER(nRet); // 手动醒目
     return 0;    
 }



因为实际上,代码被宏展开为如下形式:

int main(int argc, char** argv)
 {
     (argc); // 手动醒目
     (argv); // 手动醒目    int n;
     (n); // 手动醒目
     int nRet = printf("Hello, world!");
     (nRet); // 手动醒目
     return 0;    
 }


,即argc、argv、n和nRet确实被使用(作为一条单独的语句),所以警告不会再产生。 
如果严格按照这样一个变量一条语句的写法,代码逻辑就绝不会发生变化;同时,在release模式下,这些代码完全会被优化掉,所以对性能也不会造成影响。

另外,宏的名称UNREFERENCED_PARAMETER已经说明,这是一个未被引用的参数,所以在阅读时不仅不会造成障碍,反而会有助于理解;而在代码修改时,如果真正使用了些变量,直接将此句删除,也是很简单的一件事。

但是,实际上在Windows中,此宏仅被用来消除warning C4100: 未引用的形参警告,因为宏的名称是UNREFERENCED_ PARAMETER。所以如果在我们的项目中应用此解决方案时,最好自己定义一个名称更应景的宏,譬如:

#define UNREFERENCED_VALUE(P)          (P)

以同时完美应用于上述三种警告。

二、模板空函数PX_UNUSED()

NVIDIA的PhysX项目开发人员使用模板空函数解决方案。在PhysX开源代码的include\foundation\PxPreprocessor.h中可以找到如下定义(同时还有某些对此方法的疑问,下面各节将会回答这些疑问):

// avoid unreferenced parameter warning (why not just disable it?)
// PT: or why not just omit the parameter's name from the declaration????
template <class T> PX_CUDA_CALLABLE PX_INLINE void PX_UNUSED(T const&) {}

使用方法如下:

int main(int argc, char** argv)
 {
     PX_UNUSED(argc); // 手动醒目
     PX_UNUSED(argv); // 手动醒目    int n;
     PX_UNUSED(n); // 手动醒目
     int nRet = printf("Hello, world!");
     PX_UNUSED(nRet); // 手动醒目
     return 0;    
 }



首先,原本未被引用的变量确实被用来调用函数了,所以警告被消除。应该注意到,在PX_UNUSED()实现时有一个细节,它没有给出参数的具体名称const T&,所以警告不会再传递(见“三、为什么不应该直接删除函数参数名”)。

其次,因为仅被用来调用空函数,且是传引用方法,所以代码逻辑不会被影响;而空函数在release模式下也会被优化掉,所以也不会产生性能影响,顶多在编译时生成模板函数增加了一点点时间。

最后,此函数被使用时,同样醒目且易删除,所以也不会对代码维护造成额外的负担。

相对于宏定义的方式,我比较赞成此种解决方案,因为前者有可能因为误用而造成莫名其妙的错误。
---------------------