1. PC-Lint 是什么?
如果你真的不知道它是什么? 那么请私下询问 Google, 但千万不要声张:-).
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
简单而言, 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 系统的代码的.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
除了操作系统环境, 要想使用得顺手, 还应该把 PC-Lint 和编译/编辑环境结合起来. 现在 PC-Lint 已经能很好地和大部分主流编译/编辑器整合, 使用起来非常方便.
下文将就这两个方面进行讨论.
2.1. 配合 Linux 的使用
在 Linux 系统下, 通常使用 GCC 作为 C 代码的编译器. 为了使 PC-Lint 能有效地检查针对 Linux 的代码, 应该为它选定正确的头 (.h) 文件. 通常这些文件都放在 /usr/include 和 /usr/
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
由于 PC-Lint 不能在 Linux 系统上运行, 所以要把上面两个目录映射 (作磁盘映射) 到 Windows 系统, 这样目录就变成了 Z<注3>:\usr\include 和 Z:\usr\
为了让 PC-Lint 能认出这两个目录, 要在 std.lnt 文件中增加
-iZ:\usr\include
-iZ:\usr\3.4.3\include
两行.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
另外由于 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 目录下.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
配置好这些, 在 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 按钮即可.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
此后要对 C 文件进行检查时, 直接执行该命令即可.
3. 配置
上面的配置都是一成不变的, 配置好之后, 基本上都不需要改动了. 但对于不同的项目, 还有一些针对项目本身的特殊配置. 在这一小节, 将对针对特定项目的配置进行说明.
首先, 每个项目都有各自的头文件, 因此需要在 std.lnt 指定项目的头文件目录. 格式如下:
-i<头文件目录>
例如:
-iZ:\sw-new\src\license
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
另外, 如果项目有些目录是第三方提供的, 或者我们不关注其中的警告, 则可以把这些目录指定为库目录. 格式如下:
+libdir(<库目录1>,<库目录2>,...)
例如:
+libdir(z:\usr\include,z:\usr\3.4.3\include,z:\mysql\include)
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
对于以前没检查过的项目, 第一次使用 PC-Lint 检查时, 可能会出现很多警告和错误. 为了不至于使有用的错误掩埋于警告之中, 可以在 options.lnt 中配置全局的检查等级, 使其只显示严重的错误. 方法为:
-w<等级数>
其中等级数越大, 输入的警告错误就越多. 建议逐渐加大此数, 分步消除错误和警告. 比如先从
-w1
开始.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
还可以使用
-e<错误号>
暂时屏蔽对某个错误的检查.
4. 避免无病呻吟
也会有这样的情况: 对某些代码, 你确认----想想你的论据是否充分, 别急于下此结论哦:-)----没有问题, 但 PC-Lint 却在每次检查时都抱怨, 这时可以通过在代码作特殊注释让 PC-Lint 跳过某些检查.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
PC-Lint 提供了大量的特殊注释, 可以把这些注释加到代码中, 对代码的每个段落、每一行甚至每个表达式进
行精细的检查控制.
下面列举出一些常用的选项, 更多选项可参数 PC-Lint 的使用手册. 注意这些选项都要放到 C 代码的注释中, 且格式为 /*lint
1). -e(#[,#]...) 仅对下一个表达式有效,
a = /*lint -e(413) */ *(char *)0;
与
a = /*lint -save -e413 */ *(char *)0
/*lint -restore */;
是等价的.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
2). --e(#[,#]...) 对其所在的整个表达式有效,
a = /*lint --e(413) */ *(int *)0 + *(char *)0;
将阻止两个 413 信息的输出, 而使用 -e(413) 则只阻止第一个 413 输出.
3). -e{#[,#]...} 对下一个语句或者声明有效. 这种用法的影响范围很灵活: 当其在函数之前时, 对整个函数有效; 在某个赋值语句前, 对该个赋值语句有效; 在 if 或 while 等语句前对这整个语句段有效.
4). --e{#[,#]...} 对于其所处的 {} 号内的整个代码体有效, 这包括函数体, 类, 结构等等. 如果不处于任何 {} 号内, 则对整个文件有效 (当然, 是指从 --e{} 出现的地方至文件结束).
5). !e# 仅对其所在行有效.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
6). -esym(#,sym[,sym]) 对指定的符号屏蔽警告.
5. 常见错误处理
下面列举一些常见的错误, 及处理方法, 供参考:
525 提示错误缩进, 原因是代码中空格和 TAB 键混合使用了, PC-Lint 认为代码的缩进与代码逻辑不符合. 把代码统一改成使用空格即可<注5>.
715 符号未被引用, 原因是在函数中的某个调用参数或者局部变量没被使用. 对局部变量可以直接去掉, 对于参数则把其放到 if 语句中即可.
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
740 提示不寻常的类型转换, 通常发生在指针类型转换时, 转换前后指针所指类型空间大小不一致时. 可通过在转换前加
/*lint -e(740) */
的方式屏蔽此警告.
818 函数的指针参数在函数内部没被修改, 提示参数定义为常量指针. 按照提示在指针参数前加上 const 修饰符就可以了. 但是似乎 PC-Lint 在处理这个问题的时候有 BUG, 有时即使加了 const 修饰符还是会继续提示此警告, 此时就应该在对这个函数这个指针参数屏蔽 818 警告, 方法为在函数开始前添加
/*lint -esym(818, pointer) */
在函数结束后添加
/*lint +esym(818, pointer) */
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
827 不可到达的代码, 原因是在 while (1)/for (;;) 后还有代码, 但这些代码永远无法执行到. 解决方法是在不能执行到的代码行前加上
/*lint -unreachable */
<原创文章, 转载请注明出处. 更多精彩请访问: hi.baidu.com/qiupingwu>
<1> 并非因为是在牛年出品, 而是因为它确实本来就很牛.
<2> 这里是指当前使用的 GCC 版本, 比如 3.4.3.
<3> 假设映射到 Z 盘.
<4> 原因是 Linux 文件名区分大小写, 而 Windows 不区分.
<5> 这种工作可以由 indent 代劳, 相信它, 它能做得很好.