pclint简介

更新时间:2023-11-01 20:46:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

引言

如果能够在代码提交测试之前发现这些潜在的错误,就能够极大地减轻测试人员的压力,减少软件项目的除错成本,可是传统的C/C++编译器对此已经无能为力,这个任务只能由专用的代码检查工具完成。有很多C/C++静态代码检查工具,其中Logiscope RuleChecker和PC-Lint 是应用比较广泛的两个工具。本文将介绍如何安装和配置PC-Lint代码检查工具以及将PC-Lint 与常见的代码编辑软件,如Visual C++,Source Insight集成的方法,同时还将简要介绍一些PC-Lint常用的代码检查选项。

2介绍

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不仅能够对程序进行全局分析,识别没有被适当检验的数组下标,报告未被初始化的变量,警告使用空指针以及冗余的代码,还能够有效地帮你提出许多程序在空间利用、运行效率上的改进点。

通过下面的例子就可以看出PC-Lint 工具的强大功能: 1:

2:char *report( int m, int n, char *p ) 3:{ 4:int result; 5:char *temp; 6:long nm; 7:int i, k, kk;

8:char name[11] = \9 :

10:nm = n * m;

11:temp = p == \12:for( i = 0; i

18:if( k== 1 ) result = nm; 19:else if( kk > 0 ) result = 1; 20:else if( kk < 0 ) result = -1;

21: 22:if( m == result ) return( temp ); 23:else return( name ); 24:} 这是一段C 代码,可以通过大多数常见的C 语言编译器的检查,但是PC-Lint能够发现其中的错误和潜在的问题:第8行向name数组赋值时丢掉了结尾的nul 字符,第10行的乘法精度会失准,即使考虑到long 比int 的字长更长,由于符号位的原因仍然会造成精度失准,第11行的比较有问题,第14行的变量k没有初始化,第15行的kk可能没有被初始化,第22行的result 也有可能没有被初始化,第23行返回的是一个局部对象的地址。 随着C++语言的出现,C/C++编译器有了更严格的语法检查,但是仍然不能避免出现有BUG的程序。C++的类型检查依然不如Pascal那么严格。对于一个小程序,多数程序员都能够及时发现上面出现的错误,但是从一个拥有成千上万行代码的大型软件中找出这些瑕疵将是一项烦琐的工作,而且没有人可以保证能找出所有的这类问题。如果使用PC-Lint,只需通过一次简单的编译就可以检查出这些错误,这将节省了大量的开发时间。从某种意义上说。PC-Lint 是一种更加严格的编译器,它除了可以检查出一般的语法错误外,还可以检查出那些虽然符合语法要求,但很可能是潜在的、不易发现的错误。 3功能 PC-Lint 能够检查出很多语法错误和语法上正确的逻辑错误,PC-Lint 为大部分错误消息都分配了一个错误号,编号小于1000的错误号是分配给C 语言的,编号大于1000的错误号则用来说明C++的错误消息。 表1 列出了PC-Lint 告警消息的详细分类: 错误说明 语法错误 内部错误 致命错误 告警 消息 可选信息 C 1-199 200-299 300-399 400-699 700-800 900-999 C++ 1001-1199 1400-1699 1700-1899 1900-1999 告警级别 1 0 0 2 3 4 以C语言为例,其中的编号1-199指的是一般编译器也会产生的语法错误;编号200-299是PC-Lint 程序内部的错误,这类错误不会出现在代码中的;编号300-399指的是由于内存限制等导致的系统致命错误。编号400-999中出现的提示信息,是根据隐藏代码问题的可能性进行分类的:其中编号400-699 指的是被检查代码中很可能存在问题而产生的告警信息;编号700-899中出现的信息,产生错误的可能性相比告警信息来说级别要低,但仍然可能是因为代码问题导致的问题。编号900-999 是可选信息,他们不会被默认检查,除非你在选项中指定检查他们。 PC-Lint/FelexLint 提供了和许多编译器类似的告警级别设置选项-wLevel,它的告警级别分为以下几个级别,缺省告警级别为3级:

-w0 不产生信息(除了遇到致命的错误)

-w1 只生成错误信息-- 没有告警信息和其它提示信息 -w2 只有错误和告警信息

-w3 生成错误、告警和其它提示信息(这是默认设置) -w4 生成所有信息

PC-Lint/FelexLint还提供了用于处理函数库的头文件的告警级别设置选项

-wlib(Level),这个选项不会影响处理C/C++源代码模块的告警级别。它有和-wLevel 相同的告警级别,缺省告警级别为3级:

-wlib(0) 不生成任何库信息

-wlib(1) 只生成错误信息(当处理库的源代码时) -wlib(2) 生成错误和告警信息

-wlib(3) 生成错误、告警和其它信息(这是默认设置) -wlib(4) 产生所有信息

PC-Lint 的检查分很多种类,有强类型检查、变量值跟踪、语义信息、赋值顺序检查、弱定义检查、格式检查、缩进检查、const 变量检查和volatile变量检查等等。对每一种检查类型,PC-Lint 都有很多详细的选项,用以控制PC-Lint的检查效果。PC-Lint的选项有300多种,这些选项可以放在注释中(以注释的形式插入代码中),例如:

/*lint option1 option2 ... optional commentary */ 选项可以有多行

//lint option1 option2 ... optional commentary 选项仅为一行(适用于C++) 选项间要以空格分开,lint 命令一定要小写,并且紧跟在/*或//后面,不能有空格。如果选项由类似于操作符和操作数的部分组成,例如-esym(534, printf, scanf, operator new),其中最后一个选项是operator new,那么在operator和new 中间只能有一个空格。PC-Lint 的选项还可以放在宏定义中,当宏被展开时选项才生效。例如:

#define DIVZERO(x) /*lint -save -e54 */ ((x) /0) /*lint -restore */ 允许除数为0而不告警

下面将分别介绍PC-Lint 常用的,也是比较重要的代码检查类型,并举例介绍了各个检查类型下可能出现的告警信息以及常用选项的用法:

强类型

强类型检查选项“-strong”和它的辅助(补充)选项“-index”可以对typedef定义的数据类型进行强类型检查,以保证只有相同类型之间的变量才能互相赋值,强类型检查选项strong的用法是:

-strong( flags[, name] ... )

strong选项必须在typedef定义类型之前打开,否则PC-Lint就不能识别typedef定义的数据类型,类型检查就会失效。flags参数可以是A、J、X、B、b、l 和f,相应的解释和弱化字符在表2 中列出: 表2 强类型检查strong 选项和参数表 对强类型变量赋值时进行类型检查,这些赋值语句包括:直接赋值、返回值、参数传递、初始化。 A 后面可以跟以下字符,用来弱化A的检查强度: i 忽略初始化 r 忽略Return 语句 p 忽略参数传递 A a 忽略赋值操作 c 忽略将常量赋值(包括整数常量、常量字符串等) z 忽略Zero 赋值,Zero 定义为任何非强制转换为强类型的0 常量。 例如:0L 和(int)0 都是Zero,但是(HANDLE)0 当HANDLE 是一个强类型的时候就不是Zero。(HANDLE *)0 也不是例如使用-strong(Ai,BITS)设置,PC-Lint 将会对从非BITS类型数据向BITS 类型数据赋值的代码发出告警,但是忽略变量初始化时的此类赋值。 当把强类型的变量赋指给其他变量的时候进行类型检查。弱化参数i, r, p, a, c, z 同样适用于X X 并起相同的作用 选项是当强类型与其它类型进行如下的二进制操作时进行检查,下面是J 的参数: e 忽略==、!=和?:操作符 r 忽略>、>=、<和<= o 忽略+、-、*、/、%、|、&和^ J c 忽略该强类型与常量进行以上操作时的检查 z 忽略该强类型与Zero 进行以上操作时的检查 使用忽略意味着不会产生告警信息。举个例子,如果Meters 是个强类型,那么它只在判断相等和其他关系操作时才会被正确地检查,其它情况则不检查,在这个例子中使用J 选项是正确的。 B 选项有两个效果: 1. 出于强类型检查的目的,假设所有的Boolean 操作返回一个和Type 兼容的类型,所谓Boolean 操作就是那些指示结果为true 或false 的操作,包括前面提到的四种关系运算符和两种B 等于判断符,取反操作符!,二元操作符&&和||。 2. 在所有需要判断Bolean 值的地方,如if语句和while 语句,都要检查结果是否符合这个强类型,否则告警。 例如if(a)...当a 为int 时,将产生告警,因为int与Bolean类不兼容,所以必须改为if(a != 0)。 仅仅假定每一个Bolean 类操作符都将返回一个与Type 类型兼容的返回值。与B 选项相比,b l f b 选项的限制比较宽松。 库标志,当强类型的值作为参数传递给库函数等情况下,不产生告警。 与B或b 连用,表示抑止对1bit 长度的位域是Boolean 类型的假定,如果不选该项表示1bit 长度的位域被缺省假定为Boolean 类型。 这些选项字符的顺序对功能没有影响。但是A和J选项的弱化字符必须紧跟在它们之后。B项和b 选项不能同时使用,f选项必须搭配B选项或b 选项使用,如果不指定这些选项,-strong 的作仅仅声明type为强类型而不作任何检查。下面用一段代码演示-strong 选项的法: //lint -strong(Ab,Bool) <选项是以注释的形式插入代码中> typedef int Bool; Bool gt(int a, b) { if(a) return a > b; // OK else return 0; // Warning } 例子代码中Bool 被声明成强类型,如果没有指定b 选项,第一个return 语句中的比较操作就会被认为与函数类型不匹配。第二个return 语句导致告警是因为0不是各Bool 类型,如果添加c选项,例如-strong(Acb,Bool),这个告警就会被抑制。再看一个例子: /*lint -strong( AJXl, STRING ) */ typedef char *STRING; STRING s; ... s = malloc(20); strcpy( s, \由于malloc和strcpy是库函数,将malloc的返回值赋给强类型变量s或将强类型变量s传递给strcpy时会产生强类型冲突,不过l 选项抑制了这个告警。强类型也可用于位域,出于强类型检查的目的,先假定位域中最长的一个字段是优势Boolean 类型,如果没有优势Boolean 或位域中没有哪个字段比其它字段长,这个类型从位域被切开的位置开始成为“散”类型,例如: //lint -strong( AJXb, Bool ) //lint -strong( AJX, BitField ) typedef int Bool; typedef unsigned BitField; struct foo { unsigned a:1, b:2; BitField c:1, d:2, e:3;

本文来源:https://www.bwwdw.com/article/uev2.html

Top