Sun Studio 12:C 用户指南

4.6 lint 参考和示例

本节提供有关 lint 的参考信息,包括由 lint 执行的检查、lint 库以及 lint 过滤器。

4.6.1 由 lint 执行的诊断

对以下三种主要条件执行特定于 lint 的诊断:不一致的使用、不可移植的代码以及可疑的构造。在本节中,我们将研究在每种条件下 lint 的行为示例,并针对它们引起的问题提供可能的解决方法建议。

4.6.1.1 一致性检查

在文件内部以及各文件之间检查使用变量、参数和函数的不一致性。一般说来,对原型的使用、声明和参数执行的检查lint 对旧样式函数执行的检查相同。如果程序未使用函数原型,lint 将比编译器更严格地检查每个函数调用中参数的数量和类型。lint 还标识 [fs]printf()[fs]scanf() 控制字符串中转换定义和参数之间的不匹配。

示例:

4.6.1.2 可移植性检查

lint 的缺省行为会标记某些不可移植的代码,如果使用 -p-Xc 调用 lint 还会诊断其他一些情况。后者导致 lint 检查不符合 ISO C 标准的构造。有关使用 -p-Xc 时发出的消息,请参见4.6.2 lint

示例:


char c;
c = getchar();
if (c == EOF) ...

其中 EOF 的值为 -1,在字符变量取非负值的计算机上总是失败。使用 -p 调用的 lint 会检查暗示无格式 char 可取负值的所有比较。然而,在以上示例中,将 c 声明为 signed char 可避免执行诊断,却无法避免出现该问题。这是因为 getchar() 必须返回所有可能的字符和一个不同的 EOF 值,因此 char 无法存储其值。此示例可能是出自于实现定义的符号扩展的最常见示例,我们之所以引用该示例,是为了说明如何通过巧妙地应用 lint 的可移植性选项来帮助您发现与可移植性无关的错误。在任何情况下,将 c 声明为 int


short s;
long l;
s = l;

lint 在缺省情况下会标记所有此类赋值;可通过调用 -a 选项来禁止该诊断。请记住,使用此选项或任何其他选项调用 lint 时,可能会禁止其他诊断。请查看4.6.2 lint中的列表,以了解禁止多项诊断的选项。


int *fun(y)
char *y;
{
    return(int *)y;
}

这是因为在大多数计算机上,int 不能在一个任意字节边界上开始,而 char 则可以。可通过使用 -h 调用 lint 来禁止诊断,尽管这可能会再次禁用其他消息。但是最好通过使用通用指针 void * 来消除该问题。


int a[10];
main()
{
    int i = 1;
    a[i++] = i;
}

在此示例中,a[1] 的值在使用一个编译器时可能为 1,在使用另一个编译器时可能为 2。如果在逻辑运算符 && 的位置错误地使用了按位逻辑运算符 &,则会引起该诊断:


if ((c = getchar()) != EOF & c != ’0’)

4.6.1.3 可疑的构造

lint 会标记那些不能表达编程人员意图的各种合法构造。示例:


unsigned x;
if (x < 0) ...

总是失败。测试:


unsigned x;
if (x > 0) ...

等效于:


if (x != 0) ...

这可能不是预期的操作。lint 会标记 unsigned 变量与负常量或 0 的可疑比较。要将 unsigned 变量与负数的位模式进行比较,请将该变量的类型强制转换为 unsigned


if (u == (unsigned) -1) ...

或者使用 U 后缀:


if (u == -1U) ...

int fun()
{
    int a, b, x, y;
    (a = x) && (b == y);
}

if (x & a == 0) ...

求值如下:


if (x & (a == 0)) ...

这很有可能不是您的意图。如果使用 -h 调用 lint,则会禁用该诊断

4.6.2 lint

可以使用 lint 库检查程序是否与已在其中进行调用的库函数兼容,其中包括函数返回类型的声明以及函数所预期参数的数量和类型等。标准 lint 库与 C 编译系统提供的库对应,并且通常存储在系统上的标准位置。按照约定,lint 库的名称采用 llib-lx.ln 形式。

lint 标准 C 库 lliblc.ln 在缺省情况下附加至 lint 命令行;可通过调用 -n 选项来禁止其兼容性检查。其他 lint 库作为 -l 的参数进行访问。即:


% lint -lx file1.c file2.c

指示 lint 检查 file1.cfile2.c 中函数和变量的用法是否与 lintllib-lx.ln 兼容。仅由定义组成的库文件完全作为普通源文件和普通 .ln 文件处理,区别在于不会针对以下情况发出错误消息:函数和变量在库文件中的用法不一致,或者函数和变量在库文件中已定义但未在源文件中使用。

要创建您自己的 lint 库,请在 C 源文件的开头插入指令 NOTE(LINTLIBRARY),然后使用 -o 选项以及指定给 -l 的库名称针对该文件调用 lint


% lint -ox file1.c file2.c

导致仅将源文件中以 NOTE(LINTLIBRARY) 开头的定义写入文件 llib-lx.ln。(请注意,lint -occ -o 类似。)可以相同的方式从函数原型声明的文件创建库,不同的是必须在声明文件的最前面插入 NOTE(LINTLIBRARY)NOTE(PROTOLIB(n))。如果 n 为 1,则原型声明写入库 .ln 文件,这与旧样式的定义相同。如果 n 为 0(缺省 值),则取消该进程。使用 -y 调用 lint 是创建 lint 库的另一种方法。命令行:


% lint -y -ox file1.c file2.c

导致该行中命名的每个源文件被视为以 NOTE(LINTLIBRARY) 开头,并且只有其定义被写入 llib-lx.ln

缺省情况下,lint 在标准位置搜索 lint 库。要指示 lint 在非标准位置的目录中搜索 lint 库,请使用 -L 选项指定目录路径:


% lint -Ldir -lx file1.c file2.c

在增强模式下,lint 生成 .ln 文件,这些文件存储的信息比在基本模式下生成的 .ln 文件存储的信息多。在增强模式下,lint 可以读取和理解由基本或增强 lint 模式生成的所有 .ln 文件。在基本模式下,lint 只能读取和理解由基本 lint 模式生成的 .ln 文件。

缺省情况下,lint 使用 /usr/lib 目录中的库。这些库采用基本 lint 格式。可以运行一次 makefile,并以新格式创建增强 lint 库,从而使增强 lint 更有效地工作。要运行 makefile 并创建新库,请输入以下命令:


% cd /opt/SUNWspro/prod/src/lintlib; make

其中 /opt/SUNWspro/prod 为安装目录。运行 makefile 之后,lint 在增强模式下使用新库,而不是使用 /usr/lib 目录中的库。

系统会在搜索标准位置之前先搜索指定的目录

4.6.3 lint 过滤器

lint 过滤器是特定于项目的后处理程序,通常使用 awk 脚本或类似程序读取 lint 的输出,并放弃项目认为没有标识字符串函数真正问题的消息(例如,返回值有时或总是被忽略)。 当 lint 选项和指令未提供对输出的足够控制时,lint 过滤器会生成定制的诊断报告。

lint 的两个选项在开发过滤器的过程中特别有用: