PC-Lint之C++静态代码检查

简介:

C++语言的语法拥有其它语言所没有的灵活性,这种灵活性带来了代码效率的提升,同时也使得代码编写具有很大的随意性,另外C++编译器不进行强制类型检查,也不做任何边界检查,这就增加了代码中存在隐患的可能性。如果能够在代码提交测试之前发现这些潜在的错误,就能够极大地减轻测试人员的压力,减少软件项目的除错成本,可是传统的C++编译器对此已经无能为力,这个任务只能由专用的代码检查工具完成。

范围:

本静态代码检查工具不仅可以象普通编译器那样检查出一般语法错误,还可以检查出那些虽然完全符合语法要求,但是很可能是潜在的、不宜发现的错误。

PC-lint是GIMPEL SOFTWARE公司开发的C/C++软件代码静态分析工具,它的全称是PC-lint/FlexeLint for C/C++。PC-lint能够在Windows、MS-DOS和OS/2平台上使用,以二进制可执行文件的形式发布,而FlexeLint 运行于其它平台,以源代码的形式发布。PC-lint在全球拥有广泛的客户群,许多大型的软件开发组织都把PC-lint检查作为代码走查的第一道工序。PC-lint不仅能够对程序进行全局分析,识别没有被适当检验的数组下标,报告未被初始化的变量,警告使用空指针以及冗余的代码,还能够有效地帮你提出许多程序在空间利用、运行效率上的改进点。 

随着C++语言的出现,C++编译器有了更严格的语法检查,但是仍然不能避免出现有BUG的程序。C++的类型检查依然不如Pascal那么严格。对于一个小程序,多数程序员都能够及时发现程序出现的错误,但是从一个拥有成千上万行代码的大型软件中找出这些错误将是一项烦琐的工作,而且没有人可以保证能找出所有的这类问题。如果使用PC-lint,只需通过一次简单的编译就可以检查出这些错误,这将节省了大量的开发时间。从某种意义上说。PC-lint是一种更加严格的编译器,它除了可以检查出一般的语法错误外,还可以检查出那些虽然符合语法要求,但很可能是潜在的、不易发现的错误。

一、PC-Lint安装与配置

1.1 安装

双击运行:pclint9setup.exe。

安装目录使用默认c:\lint:

安装完成后目录:

lnt-nt.exe	PC-lint执行程序
CONFIG.exe	PC-lint配置程序
readme.txt	帮助文档的补充信息
PC-lint.pdf	帮助文档
pr.exe	打印文档
mg.txt	PC-lint的错误提示消息列表,最终根据它来修改代码
uwise.exe	卸载程序
istall.log	安装日志
_LINT.TMP	保存PC-lint检查代码后输出的错误信息,可用“记事本”打开
Lnt\… 	文件夹
co….lnt	特定编译器的配置选项
co.lnt	通用编译器的配置选项
sl-….c	非ANSI编译器的标准库模块
sl.c	非ANSI编译器的通用标准库模块
env-…lnt	各种编辑环境如Microsoft’s Visual Studio的配置文件
Lib-….lnt	特定库配置文件
Au-….lnt	作者推荐检查项的配置文件,指Scott Meyers 的 Effective C++,More Effective C++,Misra,Dan Saks的C++ Gotchas
Test\…	测试代码目录

在命令行格式下,查看安装的PC-lint版本。
命令:lint-nt -v

1.2 配置

安装完成后,进入安装目录,点击安装目录下CONFIG.exe进行配置方案的设置。

欢迎界面,提示版权信息,点击“下一步”。

显示pclint命令行使用说明窗口,点击“下一步”。

选择“Create a new STD.LNT”,使用默认的pclint路径(安装路径),然后点击“下一步”。

选择使用已有目录,点击“是”。

选择编译器,在下拉框中选择自己使用的编译器,这里是Visual 2008。点击“下一步”。

选择内存模式,可以根据自己程序区和数据区实际大小校选择一个恰当的内存模型。这里是32位。点击“下一步”。

选择所要支持的库的配置信息,选择常用的ATL、MFC、STL、Win32、Win NT等配置,点击“下一步”。

选择是否支持为使用C/C++编程提出过重要建议的作者的一些关于编程的个人意见。选择Scott Meyers(Effective C++、More Effective C++ and Effective C++ 3rd Edition),Dan Saks,MISRA 2004。点击“下一步”。

选择如何包含头文件,选择“Create –i option”,进入后选择工程所包含的头文件目录。

通过目录的方式添加你所需的所有头文件,后期可以修改该lnt文件自己手动添加。添加完成后点击“下一步”。

提示lnt文件已经被创建,点击“是”。

提示是否创建新的配置文件。这里选择“否”

选择生成一个控制全局编译信息显示情况的选项文件,选择“No”来生成该文件。点击“下一步”

点击“确定”

选择所支持的集成开发环境选项,这里选择了Visual 2008。根据自己当前的工程环境自行选择。点击“下一步”

选择“Copy LIN.BAT to one of my PATH directories”,点击“下一步”

输入PATH目录,把安装pclint的目录作为PATH目录。点击“下一步”

点击“确定”

完成配置,点击“完成”

安装完成后目录

二、环境集成

PC-lint的使用方法很简单,可以用命令行方式进行,也可以集成到开发环境中,下面就分别介绍这些用法。

2.1 与VS2008的集成

2.1.1 单个文件分析

打开Visual 2008。点击菜单“工具”->“外部工具”

点击“添加”按钮,然后输入相关信息如下:

标题	pc-lint current file(这个可以任意命名)
命令	C:\lint\lint-nt.exe(这个为lint-nt的绝对路径)
参数	-i"c:\lint" std.lnt env-vc9.lnt "$(ItemDir)$(ItemFileName)$(ItemExt)"
初始目录	$(ItemDir)

勾选“使用输出窗口”。点击“确定”

添加成功后,就可以在菜单栏下看到“pc-lint current file”

使用:

头文件:

#ifndef CPPCODE_CLASS_INTERFACECLASS_H_
#define CPPCODE_CLASS_INTERFACECLASS_H_

class InterfaceClass {
 public:
	virtual ~InterfaceClass(void);

 protected:
	InterfaceClass(void);
};

#endif  // CPPCODE_CLASS_INTERFACECLASS_H_

实现文件:

#include "InterfaceClass.h"

InterfaceClass::InterfaceClass(void) {
}

InterfaceClass::~InterfaceClass(void) {
}

点击“VS2008->工具->pc-lint current file”

检查结果:

PC-lint for C/C++ (NT) Vers. 9.00a, Copyright Gimpel Software 1985-2008

--- Module:   d:\chping\cppcheck\cppcode\cppcode\class\interfaceclass.cpp (C++)
#... ;
#... } 
};
d:\chping\cppcheck\cppcode\cppcode\class\InterfaceClass.h(10): error 963: (Note -- Qualifier const or volatile precedes a type; use +fqb to reverse the test)

--- Global Wrap-up

d:\chping\cppcheck\cppcode\cppcode\class\InterfaceClass.h(4): error 1711: (Info -- class 'InterfaceClass' (line 4, file d:\chping\cppcheck\cppcode\cppcode\class\InterfaceClass.h) has a virtual function but is not inherited, so none of its functions need to be virtual)
 error 900: (Note -- Successful completion, 2 messages produced)

2.1.2 项目文件分析

网站http://www.weihenstephan.de/~syring/win32/UnxUtils.zip下载UnxUtils.zip。需要利用unix中的find等命令来查找当前目录下的C和C++文件,然后再将它们送给lint程序处理。

解压缩UnxUtils.zip到C盘,这样路径为C:\unxutils。

类似3.1.1新建项目:

标题	pc-lint project(这个可以任意命名)
命令	C:\unxutils\pc-lint_project.bat(自建批处理文件)
参数	$(ProjectDir)
初始目录	

勾选“使用输出窗口”;点击“确定”

C:\unxutils\pc-lint_project.bat文件内容:

cd %1
set str=%1
%str:~1,2%
C:\unxutils\usr\local\wbin\find -name *.c -o -name *.cpp -o -name *.h | C:\unxutils\usr\local\wbin\xargs c:\lint\lint-nt -i"c:\unxutils\usr\local" -i"c:\lint" -u +fcp c:\lint\std.lnt c:\lint\env-vc9.lnt

使用:点击“VS2008->工具->pc-lint project”

检查结果:

C:\Windows\system32>cd "D:\chping\cppcheck\testpclint\testpclint\\" 

C:\Windows\system32>set str="D:\chping\cppcheck\testpclint\testpclint\\" 

C:\Windows\system32>D:

D:\chping\cppcheck\testpclint\testpclint>C:\unxutils\usr\local\wbin\find -name *.c -o -name *.cpp -o -name *.h   | C:\unxutils\usr\local\wbin\xargs c:\lint\lint-nt -i"c:\unxutils\usr\local" -i"c:\lint" -u +fcp c:\lint\std.lnt c:\lint\env-vc9.lnt 
PC-lint for C/C++ (NT) Vers. 9.00a, Copyright Gimpel Software 1985-2008

--- Module:   .\main.cpp (C++)
#... ;
#... } 
};
D:\chping\cppcheck\testpclint\testpclint\TestString.h(8): error 963: (Note -- Qualifier const or volatile precedes a type; use +fqb to reverse the test)

    --- Wrap-up for Module: .\main.cpp

.\main.cpp(23): error 766: (Info -- Header file 'D:\chping\cppcheck\testpclint\testpclint\TestString.h' not used in module '.\main.cpp')

--- Module:   .\TestString.cpp (C++)
 error 617: (Warning -- .\TestString.h is both a module and an include file)

--- Module:   D:\chping\cppcheck\testpclint\testpclint\TestString.h (C++)

--- Global Wrap-up

 error 900: (Note -- Successful completion, 3 messages produced)

2.2 与Source Insight的集成

2.2.1 单个文件分析

打开Source Insight。点击菜单“Options”->“Custom Commands…”

点击按钮“Add…”,添加新命令

输入“pc-lint current file”(可以随意输入),点击按钮“OK”

按如下方式输入命令及选择:

Command	pc-lint current file
Run	c:\lint\lint-nt -u -i"c:\lint" c:\lint\std.lnt c:\lint\lnt\env-si.lnt %f
Pattern	^\([^]*\)\([0-9]+\)

点击按钮“Menu…”。在弹出窗口,Menu选择Search, Menu Contents选择<end of menu>

点击按钮“Insert”

添加快捷键,点击按钮“Keys…”

点击按钮“Assign New Key…”

按下快捷键,此处是ALT+CTRL+Z

点击按钮“OK“。在Search菜单下,已加入“pc-lint current file”

示例:代码

#include <iostream>
using namespace std;

int main( void ) {
	int d = 6;
}

检查结果:

PC-lint for C/C++ (NT) Vers. 9.00a, Copyright Gimpel Software 1985-2008

--- Module:   D:\chping\cppcheck\testpclint\testpclint\main.cpp (C++)
_
}
D:\chping\cppcheck\testpclint\testpclint\main.cpp 21 Warning 438: Last value
    assigned to variable 'd' (defined at line 18) not used
D:\chping\cppcheck\testpclint\testpclint\main.cpp 18 Info 830: Location cited
    in prior message
_
}
D:\chping\cppcheck\testpclint\testpclint\main.cpp 21 Warning 529: Symbol 'd'
    (line 18) not subsequently referenced
D:\chping\cppcheck\testpclint\testpclint\main.cpp 18 Info 830: Location cited
    in prior message

2.2.2 项目文件分析

创建方式类似于3.2.1。其中命令改为:

Command	pc-lint current file
Run	C:\unxutils\usr\local\wbin\find.exe %d -name *.c -o -name *.cpp | C:\unxutils\usr\local\wbin\xargs c:\lint\lint-nt -i"c:\unxutils\usr\local" -u -i"c:\lint" c:\lint\std.lnt c:\lint\lnt\env-si.lnt %f
Pattern	^\([^]*\)\([0-9]+\)

示例:直接显示检查结果

2.3 命令行模式

2.3.1 单个文件分析

命令:c:\lint\lint-nt.exe -i”c:\lint” std.lnt env-vc9.lnt 文件路径+文件名

2.3.2 项目文件分析

自建批处理文件pc-lint_projectcmd.bat。

C:\unxutils\usr\local\wbin\find "D:/chping/cppcheck/testpclint/testpclint" -name *.c -o -name *.cpp -o -name *.h | C:\unxutils\usr\local\wbin\xargs c:\lint\lint-nt -i"c:\lint"  -u +fcp c:\lint\std.lnt

其中”D:/chping/cppcheck/testpclint/testpclint”指的是工程目录。检查其他工程时,替换该目录即可。

处理结果如下:

如果不希望在批处理文件中加入目录功能,如下:

C:\unxutils\usr\local\wbin\find -name *.c -o -name *.cpp -o -name *.h | C:\unxutils\usr\local\wbin\xargs c:\lint\lint-nt -i"c:\lint"  -u +fcp c:\lint\std.lnt
C:\unxutils\usr\local\wbin\find -name *.c -o -name *.cpp -o -name *.h | C:\unxutils\usr\local\wbin\xargs c:\lint\lint-nt -i”c:\lint”  -u +fcp c:\lint\std.lnt

这样的话,只需要在命令模式下,将当前目录直接定位到工程目录即可:

三、PC-Lint的使用

3.1 错误信息

3.1.1 错误信息号

PC-lint能够检查出很多语法错误和语法上正确的逻辑错误,PC-lint为大部分错误消息都分配了一个错误号,编号小于1000的错误号是分配给C语言的,编号大于1000的错误号则用来说明C++的错误消息。下表列出了PC-lint告警消息的详细分类:

以C语言为例:

3.1.2 错误信息警告级别

PC-lint提供了和许多编译器类似的告警级别设置选项。

-wLevel,它的告警级别分为以下几个级别,缺省告警级别为-w3级:

-w0	不产生信息(除了遇到致命的错误)
-w1	只生成错误信息 -- 没有告警信息和其它提示信息
-w2	只有错误和告警信息
-w3	生成错误、告警和其它提示信息(这是默认设置)
-w4	生成所有信息

3.1.3 错误信息禁止选项说明

3.1.4 常用告警分析及解决措施

所举的例子都是假设不好改的前提下,进行屏蔽的方法。

告警级别1,例如:

int main( void ) {
	a++;
}
.\main.cpp(15): error 40: (Error -- Undeclared identifier 'a')
.\main.cpp(15): error 52: (Error -- Expected an lvalue)

告警号40,属于1级告警级别:

/*lint -esym(40, a)*/a++;

告警级别2,例如:

int main( void ) {
double d = 6;
	int a = d;
}
.\main.cpp(26): error 438: (Warning -- Last value assigned to variable 'a' (defined at line 25) not used)

告警号438,属于2级告警级别 :

/*lint -esym(438, a)*/int a = d;

告警级别3,例如:

int main( void ) {
	int d = 6;

	switch(d) {
	case 1:
		break;
	}
}
.\main.cpp(23): error 744: (Info -- switch statement has no default)

告警号744,属于3级告警级别:

switch(d) {/*lint -e744 */
case 1:
	break;
}

3.1.5 错误信息查询

参考PC-lint安装目录下帮助文档《PC-lint.pdf》,有详细说明。

3.1.6 常用命令

参考PC-lint安装目录下帮助文档《PC-lint.pdf》,有详细说明。

发表回复