您的位置:首页 > 运维架构 > Linux

linux pc-lint强大的静态代码检查工具

2012-09-04 18:12 267 查看
1. PC-Lint 是什么?

  如果你真的不知道它是什么? 那么请私下询问 Google, 但千万不要声张:-).

  简单而言, PC-Lint 是 Gimpel Software 公司出品的一个很牛<注1>的软件, 你可以叫它吹毛求疵器, 因为它能够做比编译器严格得多的(包括但不限于)语法检查.

  事实上这个工具有两个版本: 一个叫 PC-Lint, 是针对 PC 机的 (主要是对付 Windows, MS-DOS, OS/2 等系统), 以可执行文件形式发布; 另一个叫 FlexeLint, 是针对其它系统的 (比如 Linux), 采用源码方式发布.

  由于很少见到 FlexeLint, 本文仅就 PC-Lint 的使用进行介绍. 目前在官方网上出现的最新版本是 9.0, 但同样不易获得, 所以本文只介绍 PC-Lint8.0. 我们将采用变通的方法实现对 Linux 系统下的代码检查.

2. 使用环境

  正如前面所说, PC-Lint 本来只当游弋于 Windows, OS/2 之上, 但由于 C 的标准化做得比较好, 所以稍作变通, PC-Lint 是完全有能力对付那些针对 Linux 系统的代码的.

  除了操作系统环境, 要想使用得顺手, 还应该把 PC-Lint 和编译/编辑环境结合起来. 现在 PC-Lint 已经能很好地和大部分主流编译/编辑器整合, 使用起来非常方便.

  下文将就这两个方面进行讨论.

2.1. 配合 Linux 的使用

  在 Linux 系统下, 通常使用 GCC 作为 C 代码的编译器. 为了使 PC-Lint 能有效地检查针对 Linux 的代码, 应该为它选定正确的头 (.h) 文件. 通常这些文件都放在 /usr/include 和 /usr/<x.y.z>/include
目录下.

  由于 PC-Lint 不能在 Linux 系统上运行, 所以要把上面两个目录映射 (作磁盘映射) 到 Windows 系统, 这样目录就变成了 Z<注3>:/usr/include
和 Z:/usr/<x.y.z>/include. 也可以把 Linux 的头文件直接 COPY 到 Windows 系统中, 这时系统会提示文件重名, 但这些文件一般用不到, 直接覆盖就行.

(我是直接拷贝到windows下c:/pclint/usr下,不过没有拷贝/usr/<x.y.z>/include)

  为了让 PC-Lint 能认出这两个目录, 要在 std.lnt 文件中增加

-iZ:/usr/include

-iZ:/usr/3.4.3/include

两行.

  另外由于 PC-Lint 是针对 Windows 设计的, 会抱怨 Linux 某些头文件不正确. 由于我们不提倡自己修改标准文件, 因此干脆让 PC-Lint 暂时失声好了. 这可以通过在 options.lnt 文件增加下面几行实现:

-e716 // allow use while (1)

// bug in syslog.h, it define __need_va_list_ macro

-efile(537,stdarg.h)

-emacro(530,va_start) // do not init first parameter

修改 options.lnt 文件, 使用 gnu 检查规则, 即应该有如下一行:

c:/pclint/lnt/co-gnu3.lnt

假设 PC-Lint 安装在 C:/pclint 目录下.

  配置好这些, 在 Windows 上检查 Linux 代码就应该比较顺手了.

2.2. 配合 SourceInsight 的使用

  在 SourceInsight 中可以新建一个命令. 通过 Custom Commands 窗口, 在其中的 Command 中填入命令名 (比如是 lint), 再在 Run 中 填入

C:/pclint/LINT-NT.EXE -u -ic:/pclint/lnt std.lnt env-si %f

再在 Pattern 框里填写

^/(.*/.[a-zA-Z]+/)/w/([0-9]+/).*

然后点击 Add 按钮即可.

  此后要对 C 文件进行检查时, 直接执行该命令即可.

3. 配置

  上面的配置都是一成不变的, 配置好之后, 基本上都不需要改动了. 但对于不同的项目, 还有一些针对项目本身的特殊配置. 在这一小节, 将对针对特定项目的配置进行说明.

  首先, 每个项目都有各自的头文件, 因此需要在 std.lnt 指定项目的头文件目录. 格式如下:

-i<头文件目录>

例如:

-iZ:/sw-new/src/license

  另外, 如果项目有些目录是第三方提供的, 或者我们不关注其中的警告, 则可以把这些目录指定为库目录. 格式如下:

+libdir(<库目录1>,<库目录2>,...)

例如:

+libdir(z:/usr/include,z:/usr/3.4.3/include,z:/mysql/include)

  对于以前没检查过的项目, 第一次使用 PC-Lint 检查时, 可能会出现很多警告和错误. 为了不至于使有用的错误掩埋于警告之中, 可以在 options.lnt 中配置全局的检查等级, 使其只显示严重的错误. 方法为:

-w<等级数>

其中等级数越大, 输入的警告错误就越多. 建议逐渐加大此数, 分步消除错误和警告. 比如先从

-w1

开始.

  还可以使用

-e<错误号>

暂时屏蔽对某个错误的检查.

4. 避免无病呻吟

  也会有这样的情况: 对某些代码, 你确认----想想你的论据是否充分, 别急于下此结论哦:-)----没有问题, 但 PC-Lint 却在每次检查时都抱怨, 这时可以通过在代码作特殊注释让 PC-Lint 跳过某些检查.

  PC-Lint 提供了大量的特殊注释, 可以把这些注释加到代码中, 对代码的每个段落、每一行甚至每个表达式进

行精细的检查控制.

  下面列举出一些常用的选项, 更多选项可参数 PC-Lint 的使用手册. 注意这些选项都要放到 C 代码的注释中, 且格式为 /*lint <xxxx> */, 其中 lint 必须紧接在 /* 后面出现, <xxxx> 表示选项, 选项后留一个空格, 然后才是 */.

  1). -e(#[,#]...) 仅对下一个表达式有效,

  a = /*lint -e(413) */ *(char *)0;



  a = /*lint -save -e413 */ *(char *)0

  /*lint -restore */;

是等价的.

  2). --e(#[,#]...) 对其所在的整个表达式有效,

  a = /*lint --e(413) */ *(int *)0 +
*(char *)0;

将阻止两个 413 信息的输出, 而使用 -e(413) 则只阻止第一个 413 输出.

  3). -e{#[,#]...} 对下一个语句或者声明有效. 这种用法的影响范围很灵活: 当其在函数之前时, 对整个函数有效; 在某个赋值语句前, 对该个赋值语句有效; 在 ifwhile 等语句前对这整个语句段有效.

  4). --e{#[,#]...} 对于其所处的 {} 号内的整个代码体有效, 这包括函数体, 类, 结构等等. 如果不处于任何 {} 号内, 则对整个文件有效 (当然, 是指从 --e{} 出现的地方至文件结束).

  5). !e# 仅对其所在行有效.

  6). -esym(#,sym[,sym]) 对指定的符号屏蔽警告.

5. 常见错误处理

  下面列举一些常见的错误, 及处理方法, 供参考:

  525 提示错误缩进, 原因是代码中空格和 TAB 键混合使用了, PC-Lint 认为代码的缩进与代码逻辑不符合. 把代码统一改成使用空格即可<注5>.

  715 符号未被引用, 原因是在函数中的某个调用参数或者局部变量没被使用. 对局部变量可以直接去掉, 对于参数则把其放到 if 语句中即可.

  740 提示不寻常的类型转换, 通常发生在指针类型转换时, 转换前后指针所指类型空间大小不一致时. 可通过在转换前加

  /*lint -e(740) */

的方式屏蔽此警告.

  818 函数的指针参数在函数内部没被修改, 提示参数定义为常量指针. 按照提示在指针参数前加上 const 修饰符就可以了.
但是似乎 PC-Lint 在处理这个问题的时候有 BUG, 有时即使加了 const 修饰符还是会继续提示此警告, 此时就应该在对这个函数这个指针参数屏蔽 818 警告, 方法为在函数开始前添加

  /*lint -esym(818, pointer) */

在函数结束后添加

  /*lint +esym(818, pointer) */

  827 不可到达的代码, 原因是在 while (1)/for (;;) 后还有代码,
但这些代码永远无法执行到. 解决方法是在不能执行到的代码行前加上

  /*lint -unreachable */

  <1> 并非因为是在牛年出品, 而是因为它确实本来就很牛.

  <2> 这里是指当前使用的 GCC 版本, 比如 3.4.3.

  <3> 假设映射到 Z 盘.

  <4> 原因是 Linux 文件名区分大小写, 而 Windows 不区分.

  <5> 这种工作可以由 indent 代劳, 相信它, 它能做得很好.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: