转载请标明出处:blog.youkuaiyun.com/zhangxingping
关于编译警告
编写用于计算1+2+3+…+10的结果的程序。用Visual Studio 2010创建空的控制台程序后,增加cpp文件如下:
#include <iostream>
using namespace std;
int main()
{
int sum = 0;
//int sum;
int count = 10;
while(count)
{
sum+=count--;
}
cout << sum;
return 0;
}
编译结果如下:
1>------ Build started: Project: test, Configuration: Debug Win32 ------
1> main.cpp
1> test.vcxproj -> C:\Documents and Settings\Administrator.B3E312BBC82943B\桌面\test\Debug\test.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
可见,没有编译警告。
如果上面的程序由于某种原因而被错误地写成了:
#include <iostream>
using namespace std;
int main()
{
//int sum = 0;
int sum;
int count = 10;
while(count)
{
sum+=count--;
}
cout << sum;
return 0;
}
则编译结果如下:
1>------ Build started: Project: test, Configuration: Debug Win32 ------
1> main.cpp
1>c:\documents and settings\administrator.b3e312bbc82943b\桌面\test\test\main.cpp(13): warning C4700: uninitialized local variable 'sum' used
1> test.vcxproj -> C:\Documents and Settings\Administrator.B3E312BBC82943B\桌面\test\Debug\test.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
从输出结果可以看出有一个变了没有初始化的警告。从语法的角度来讲,变量没有初始化时没有错误的。但是使用没有初始化的变量存在潜在的风险,特别是当没有初始化的变量被用作右值得时候,往往是一个错误。上面示例程序中的sum变量没有进行初始化实际上就是一个错误,会导致程序不能正确计算出结果。
在Visual Studio IDE中,工程的属中有如下关于警告的设置: Properties->Configuration Properties->c/c++->Warning Level。这个设置可以选择W0-W4,Wall以及inherit from parent or project default 共计7个选项。这些选项的具体含义参见:http://msdn.microsoft.com/en-us/library/thxezb7y.aspx 。同时该文档中也提到:For a new project, it may be best to use /W4 in all compilations. This will ensure the fewest possible hard-to-find code defects. 也就是说,对于新建的工程,把编译警告项最好设置为W4。因为这样可以尽量避免那些难以定位的缺陷。
日常工作中,有项目可能是旧的,也有的可能是新的。针对新的项目,强烈建议工程属性中的警告级别设置为W4,并要求编译结果中出现的警告要被全部消除。这样做的目的是尽量在编译阶段就消灭这些潜在的问题。这样做可能需要花费一定的时间。但是从实践中来看,消灭这些警告所花费的时间,人力和资源相对于一个潜在故障在测试阶段被发现并进行定位修正所花费的时间,人力和精力来说是很少的。一般开发过程中都定义了很多的规则来尽量把问题暴露在开发的前期阶段。因为此时解决这些问题的代价相对来要低很多。比如,编程规范中有诸如与常量进行比较的时候,常量要写在==的左侧等都是为了达到这样的目的。
项目开发的实际过程中往往出现以下的问题:
1. 新建的工程中没有关于警告级别的限制。开发人员随意设置工程的编译警告级别,有的工程的警告级别甚至被设置为W0。
2. 即使设定了项目的警告级别,编译报告的警告还是没有被消除,编译时还有大量的警告存在。有心的程序员还可能会去查看一下这些警告是否蕴藏着错误;绝大多数人员都是不会关心这些警告的,只是关心错误。(错误不能不关心呀,否则无法运行程序)
3. 为了消除这些警告,不假思索地使用#pragma warning(disable XXX)。
这些做法都违背了开发中应该尽早暴露潜在问题并提早解决这些问题的原则。
针对老的工程,可以不必重新设置项目的警告级别,但是需要保证新增或者修改的代码中不再引入W4级别的警告。也就是说新增或者修改的代码应该按照新工程的原则来处理,即所有的W4警告都应该被消除。
文中开头的示例程序就表明了消除警告确实可以达到早期发现故障,并及时纠正的目的。缺陷越是在开发的后期被发现,定位,修正缺陷所需要的代价(时间,精力,人力)往往越高。反之亦然。上述示例照哦给你的缺陷的定位和修正可能很简单,有经验的开发人员一眼就能看出问题的所在,并进行修正。然而,现代应用程序往往是大型的,少则几万行代码,多则几十万行的代码。这样复杂的程序如果出现了类似的问题,定位和修正可就不那么简单了,甚至发现问题的代价都很高。与其加班定位问题,不如提早避免问题的发生。“能者解决问题,智者避免问题”。
规则8:新建项目的设置中必须把警告的级别设置为W4,并且要求消除所有的编译警告。旧项目中的新增代码也要遵循上述原则。使用#pragma warning(disable XXX)方式的必须明确给出书面的原因说明。