PC-Lint是GIMPEL SOFTWARE公司的一个产品。它是一个历史悠久,功能异常强劲的静态代码检测工具。它的使用历史可以追溯到计算机编程的远古时代(30多年以前)。经过这么多年的发展,它不但能够监测出许多语法逻辑上的隐患,而且也能够有效地帮你提出许多程序在空间利用、运行效率上的改进点。在很多专业级的软件公司,比如Microsoft、华为,PC-Lint检查无错误无警告是代码首先要过的第一关。
C/C++语言的灵活性带来了代码效率的提升,但相应带来了代码编写的随意性,另外C/C++编译器不进行强制类型检查,也带来了代码编写的隐患。PCLint识别并报告C/C++语言中的编程陷阱和格式缺陷的发生。它进行代码的全局分析,能识别没有被适当检验的数组下标,报告未被初始化的变量,警告使用空指针,冗余的代码,等等。软件除错是软件项目开发成本和延误的主要因素。PClint能够帮你在程序动态测试之前发现编码错误。这样消除错误的成本更低。
使用PC-Lint在代码走读和单元测试之前进行检查,可以提前发现程序隐藏错误,提高代码质量,节省测试时间,规范软件人员的编码行为。
1) PC-Lint是一种静态代码检测工具,不仅可以象普通编译器那样检查出一般的语法错误,还可以检查出那些虽然完全合乎语法要求,但很可能是潜在的、不易发现的错误。
2) PC-lint不但可以检测单个文件,也可以从整个项目的角度来检测问题,因为C/C++语言编译器固有的单个编译,这些问题在编译器环境下很难被检测,而PC-Lint在检查当前文件的同时还会检查所有与之相关的文件,可想而知,它会对我们有很大的帮助。
3) PC-lint支持几乎所有流行的编辑环境和编译器,比如Borland C++从1.x到5.x各个版本、Borland C++ Build、GCC、VC,VC.net、watcom C/C++、Source insight、intel C/C++等等,也支持16/32/64的平台环境。
4) 支持Scott Meyes的名著(Effective C++/More Effective C++)中说描述的各种提高效率和防止错误的方法。
将压缩包比如PC.Lint.v8.00e.zip解压到某个目录下,比如X:/develop/PC.Lint.v8.00e,即可使用;为了后续设置的方便,可以设置PC-Lint的环境变量:右击“我的电脑”,选择“属性”,通过“系统属性-->高级-->环境变量”设置系统变量PCLINT_ROOT为X:/develop/PC.Lint.v8.00e。如下图所示:
Q:如何查看版本?
A:见%PCLINT_ROOT%/readme.txt:
PC-lint for C/C++ Version 8.00e
PC-lint支持几乎所有流行的编译器和IDE环境,它是以命令行加配置文件的形式进行使用的,所以其使用习惯跟现在常见的windows软件不同。
首先我们先研究一下最原始的用法—命令行,然后再研究与各种编辑器集成的方法。
先在E:/建一个文件:main.cpp,内容为:
void main() { } |
在命令行下输入:%PCLINT_ROOT%/Lint-nt E:/main.cpp
E:/>%PCLINT_ROOT%/Lint-nt E:/main.cpp PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001
--- Module: E:/main.cpp _ }
E:/main.cpp 6 Info 783: Line does not end with new-line |
PCLINT已经工作了,是不是简单的难以让人相信。
建立一个文件:E:/main.cpp,内容为:
#include <stdio.h>
void main() { printf("hello pclint/n"); } |
再次在命令行下输入:%PCLINT_ROOT%/Lint-nt E:/main.cpp
E:/>%PCLINT_ROOT%/Lint-nt E:/main.cpp PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001
--- Module: E:/main.cpp _ #include <stdio.h> E:/main.cpp 1 Error 322: Unable to open include file 'stdio.h' |
报错误,“不能找到头文件stdio.h”。当然PCLINT不可能也不应该知道到哪里去找stdio.h,stdio.h所在的路径需要我们告诉它。如何告诉呢?通常的做法是在xxx.lnt文件中指定,然后指定使用这个xxx.lnt文件。
? 配置std.lnt
手工配置std.Lnt(或者使用%PCLINT_ROOT%/CONFIG.EXE)。为了便于区分,更名为cmd_std.Lint。内容为:
// Microsoft C and Visual C++ 6.x, -si4 -sp4, // Standard lint options
co-msc60.lnt
// options.lnt -si4 -sp4 -i"E:/Program Files/Microsoft Visual Studio/VC98/Include" -i"E:/Program Files/Microsoft Visual Studio/VC98/MFC/INCLUDE" -i"E:/Program Files/Microsoft Visual Studio/VC98/ATL/INCLUDE"
|
暂时将options.lnt这行注释掉。
? 使用std.lnt
再次在命令行下输入:%PCLINT_ROOT%/Lint-nt -i"%PCLINT_ROOT%" -u cmd_std.lnt e:/main.cpp
Q:-i"%PCLINT_ROOT%" -u cmd_std.Lint表示什么意思?
A:-i"%PCLINT_ROOT%" -u cmd_std.Lnt 指明使用std.lnt这个选项文件,至于std.lnt在什么目录,通过-i"%PCLINT_ROOT%"告知。
至此,我们已经学会了PCLINT的简单用法及两个选项:-i,-u
-i指明包含路径
-u指明使用哪些.lnt文件
前面我们掌握了命令行方式下PCLINT的使用方法,下面介绍在几种常见开发工具VC、VS 2005、Source Insight下面的配置及使用。
新建一vc_std.lnt文件在%PCLINT_ROOT%中,并将添加上以下的内容:
在VC上选择“工具-->定制”,点击“工具”tab页。新建一自定义工具项,名称为:pc-lint(可以为其它名称)。其中的Arguments为:
-i"X:/develop/PC.Lint.v8.00e" -u vc_std.lnt env-vc6.lnt "$(FileName)$(FileExt)"。如图所示:
设置好之后就可以通过点击“工具-->pc-lint”来进行代码检查啦。
Q:怎么知道要输入这样的参数了?
A:从帮助中得知的,见文件%PCLINT_ROOT%/env-vc6.lnt
Q: env-vc6.lnt有什么作用?
A:指定输出错误报告的格式,这个选项可以去掉,比如修改为:
Arguments为:-i"X:/develop/PC.Lint.v8.00e" -u vc_std.lnt "$(FileName)$(FileExt)"
新建一vs_std.lnt文件在主目录中,并将添加上以下的内容
注意:一系列xxx.lnt是语法配置规则,决定了按什么规则进行检查,以后可以根据需要进行增减.
在vs2005中的“工具->外部工具”中,点击“添加”,新建一个外部工具。标题可以任意,可取pc-lint-vs;命令为:%PCLINT_ROOT%/lint-nt.exe;参数为:-i"%PCLINT_ROOT%" -u vs_std.lnt "$(ItemDir)$(ItemFileName)$(ItemExt)";初始目录为:$(ItemDir),并将下面的“使用输出窗口”勾选上。如图所示:
设置好之后就可以通过点击“工具-->pc-lint-vs”来进行代码检查了。
新建一si_std.lnt文件在主目录中,并将添加上以下的内容:
在Source Insight中,设置方法如下:
1) 从Options菜单中选择“Custom Commands”命令项;
2) 在Name栏中输入“PC-lint ”,这个名称可以随便起,只要清晰即可;在Run栏中输入
“X:/develop/PC.Lint.v8.00e/lint-nt.exe -i"X:/develop/PC.Lint.v8.00e" -u " X:/develop/PC.Lint.v8.00e/si_std.lnt" X:/develop/PC.Lint.v8.00e /lnt/env-si.lnt %f”
3) 在Output栏中选择“Iconic Window”、“Capture Output”;
4) 在Control栏中选择“Save Files First”;
5) 在Source Links in Output栏中选择“Parse Links in Output”、“File,then Line”
6) 在Pattern栏中输入“^/([^ ]*/) /([0-9]+/)”;
7) 点Add键加入该命令;
8) 点右侧 Menu--->Menu-->View--><end of menu>, 右侧Insert, OK;
此时在SourceInsight中的View菜单下多了个pc-lint选项,可以用它来一个工程中的C/C++文件进行静态检查。
下面以VS 2005为例,说明PC-Lint的使用。
新建一个最简单的Win32 Console Application,工程名testForPclint1,其中的main.cpp为:
点击工具菜单下面的pc-lint-vs菜单项:
PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001
--- Module: c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp _ }
c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(5) : Info 783: Line does not end with new-line |
第五行有个Info级的错误:Info 783: Line does not end with new-line
意思是说没有以新行结束。
修改main.cpp为:
再次LINT,结果没有任何告警:
PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001
--- Module: c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp |
新建一个最简单的Win32 Console Application,工程名testForPclint2,其中的main.cpp为:
点击工具菜单下面的pc-lint-vs菜单项:
PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001
--- Module: c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp _ int* b = new int; c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(8) : Warning 527: Unreachable _ return 0; c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(9) : Warning 429: Custodial pointer 'b' (line 8) has not been freed or returned c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(8) : Info 830: Location cited in prior message _ } c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(10) : Warning 529: Symbol 'a' (line 6) not subsequently referenced c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(6) : Info 830: Location cited in prior message _ } c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(10) : Warning 529: Symbol 'b' (line 8) not subsequently referenced c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(8) : Info 830: Location cited in prior message _ } c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(10) : Info 715: Symbol 'argc' (line 4) not referenced c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp(4) : Info 830: Location cited in prior message
--- Wrap-up for Module: c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp
Info 766: Header file 'D:/Program Files/Microsoft Visual Studio/VC98/Include/stdio.h' not used in module 'c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp'
|
有14个告警,修改main.cpp为:
int main() { int* b = new int; delete b; return 0; }
|
再次LINT,无任何告警了。
PC-lint for C/C++ (NT) Ver. 8.00e, Copyright Gimpel Software 1985-2001
--- Module: c:/Documents and Settings/Admin/My Documents/Visual Studio 2005/Projects/testForPclint1/testForPclint1/main.cpp |
为什么要使用批处理?还不是为了使用更简单。要使用批量处理需要在windows下使用一些Unix命令。解压附带的UnxUtils.zip到X:/develop/UnxUtils目录下,以后就可以直接使用这些命令写批量脚本进行处理啦。
假如我们代码的根目录为E:/try,这个目录下还有子目录,我们在所要批量检查的代码的根目录建一个批处理文件lint_project.bat,内容为:
X:/develop/UnxUtils/usr/local/wbin/find.exe "E:/try" -name *.c -o -name *.cpp |X:/develop/UnxUtils/usr/local/wbin/xargs.exe %PCLINT_ROOT%/lint-nt.exe -i"%PCLINT_ROOT%" -u vs_std.lnt |
运行lint_project.bat:lint_project.bat > pclint.out。这样就可以在pclint.out中得到所有文件的检查结果啦。
前面我们学习了如何使用PC-Lint工具,最后我们总结一些常用文件的使用方法。
Msg.txt :解释告警的内容。根据告警的ID可以找到对应的解释、解决方法。
选用的.lnt :包含头文件的路径,-i选项。
env-选用的编辑环境.lnt :讲述如何将PC-lint与对应的编辑环境结合起来。如VC的设置可以见%PCLINT_ROOT%/env-vc6.lnt。
co-xxx.lnt :选定的编译器。
std.lint :内存模型等全局性东西。
LIB-xxx.LNT :库类型的列表,包括标准C/C++库,MFC库,OWL库等等。
AU-xxx.LNT :C++编程提出过重要建议的作者,选择某作者后,他提出的编程建议方面的选项将被打开。
OPTIONS.LNT :反映全局编译信息显示情况的选项文件。如:
PC-Lint选项可以放在注释中,例如:
/*lint option1 option2 ... optional commentary */
//lint option1 option2 ... optional commentary
假如有充分的理由证明自己的代码没问题,想屏蔽掉某个PC-Lint选项,可以在注释中屏蔽:
或
选项间要以空格分开,lint命令一定要小写,并且紧跟在/*或//后面,不能有空格。如果选项由类似于操作符和操作数的部分组成,例如-esym(534, printf, scanf, operator new),其中最后一个选项是operator new,那么在operator和new中间只能有一个空格。
选项还可以放在宏定义中,例如:
PC-Lint的选项很多共有300多种,大体可分为以下几类:
1) 错误信息禁止选项
该类选项是用于禁止生成某类错误信息的选项,最常用的是-e和+e,-e是禁止生成某类错误信息,+e是恢复生成某类错误信息。
-w 对于所有大于级别的告警信息都不显示。
-wlib()对于所有大于级别的关于库函数数的告警信息都不显示。我们可以用-wlib(0)来屏蔽所有的库函数的告警信息,-wlib(1)只显示库函数中的句法错误。
-esym(#,) 可以屏蔽对于特定符号的某告警信息。
2) 变量类型大小选项
不同的目标机、编译系统变量类型的的大小(如短整形变量、整形变量等)会有所不同,该类选项用于为目标机设置变量类型的大小。由于默认的设置与大部分的编译器是匹配的,这些专门的设置通常情况下是不需要的,只在特别的目标机结构中才用。例如一个M68000目标机,它的int类型和指针类型通常是32bit的,这时你应该使用选项:-si4 -sp4。这些尺寸参数的当前值可以通过help屏来获得,例如可以输入以下命令行: lint -si4 -sp4 ?
3) 冗长信息选项
冗长信息指的是LINT过程中产生的一些与编译过程有关的信息,而不是真正的告警信息、错误信息等。是否生成这些信息可以通过-v和+v选项来决定。+v是生成这些信息,-v是关闭这些信息,这组选项中除+v外,其它所有选项都可以关闭+v选项。
4) 标记选项
以+f、++f、-f和--f开头的选项是标记选项。他们的逻辑含义分别如下:
+f...:通过把标志置为1而把它置为ON
-f...:通过把标志置为0而把它置为OFF
++f...:标志增1
--f...:标志减1
后面两个用于你想在局部把一个标志置为ON的情况,而不影响全局设置。例如你可以这样使用:
标记选项的种类很多,基本含义是用于打开或关闭某类语法情况使用,例如允许使用缩写结构体名称,允许使用无名联合体,把所有模块当作C++编译等。
5) 消息显示选项
消息显示选项用于定义消息输出格式。主要有消息高度选项、消息宽度选项、消息格式选项等。
6) 其它选项
其它选项中的种类很多,各种类间差异很大,在这里就不一一介绍了,建议大家看一看《PC-LINT》一书,第五章有对每种选项的详细说明。我自己也没看过,呵呵。实际上前面提到的东西已经够用了。
PC-Lint在代码走读和单元测试之前进行检查,以便提前发现程序隐藏错误,提高代码质量,节省测试时间,规范编码行为。
新开发的代码必须使用PC-Lint进行检查,修改的代码涉及到的文件也需要使用PC-Lint进行检查。
对于Warning及Warning级别以上的错误,存在安全的隐患,是一定得解决的。对于确实无法解决,有充分理由证明代码没问题的,可以通过注释的方式进行屏蔽,并在质量文档中进行记录。
对于Info级别的错误,是对程序优化的建议,建议尽量解决,但不强制。