一些不可移植的代码在其缺省行为中带有 lint 标志,当用 -p 或 -Xc 调用 lint 时,会诊断额外的几种情况。后者导致 lint 检查不符合 ISO C 标准的构造。有关使用 -p 和 -Xc 时发出的消息,请参见4.6.2 lint 库。
示例:
在某些 C 语言实现中,未显式声明为 signed 或 unsigned 的字符变量会被视为范围通常在 -128 到 127 之间的带符号值。在其他实现中,它们会被视为范围通常在 0 到 255 之间的非负值。因此测试:
char c; c = getchar(); if (c == EOF) ... |
其中 EOF 的值为 -1,在字符变量取非负值的计算机上总是失败。使用 -p 调用的 lint 会检查暗示无格式 char 可取负值的所有比较。然而,在以上示例中,将 c 声明为 signed char 可避免执行诊断,却无法避免出现该问题。这是因为 getchar() 必须返回所有可能的字符和一个不同的 EOF 值,因此 char 无法存储其值。此示例可能是出自于实现定义的符号扩展的最常见示例,我们之所以引用该示例,是为了说明如何通过巧妙地应用 lint 的可移植性选项来帮助您发现与可移植性无关的错误。在任何情况下,将 c 声明为 int。
位字段也会出现类似的问题。将常量值赋给位字段时,该字段可能太小,无法容纳该值。在将 int 类型的位字段视为无符号值的计算机上,int x:3 所允许的值在 0 到 7 的范围内;而在将其视为带符号值的计算机上,相应值的范围在 -4 到 3 之间。但是,声明为类型 int 的三位字段无法在后一种计算机上存储值 4。使用 -p 调用的 lint 会标记除 unsigned int 和 signed int 之外的所有位字段类型。它们仅是可移植的位字段类型。编译器支持 int、char、short 和 long 位字段类型,它们可以为 unsigned、 signed 或无格式。编译器还支持 enum 位字段类型。
在将较长的类型赋值给较短的类型时,会出现错误。如果有效位被截断,则失去准确性:
short s; long l; s = l; |
lint 在缺省情况下会标记所有此类赋值;可通过调用 -a 选项来禁止该诊断。请记住,使用此选项或任何其他选项调用 lint 时,可能会禁止其他诊断。请查看4.6.2 lint 库中的列表,以了解禁止多项诊断的选项。
一个对象类型指针向具有更严格对齐要求的对象类型指针的强制类型转换可能不可移植。lint 标记以下代码:
int *fun(y) char *y; { return(int *)y; } |
这是因为在大多数计算机上,int 不能在一个任意字节边界上开始,而 char 则可以。可通过使用 -h 调用 lint 来禁止诊断,尽管这可能会再次禁用其他消息。但是最好通过使用通用指针 void * 来消除该问题。
ISO C 未定义复杂表达式的求值顺序。也就是说,如果由于某个表达式的求值而更改某个变量时,函数调用、嵌套赋值语句或加减运算符会引起副作用,那么副作用发生的顺序在极大程度上取决于计算机。在缺省情况下,lint 会标记由于副作用而更改并且在同一表达式的其他地方使用的任何变量:
int a[10]; main() { int i = 1; a[i++] = i; } |
在此示例中,a[1] 的值在使用一个编译器时可能为 1,在使用另一个编译器时可能为 2。当按位逻辑运算符 & 被错误地代替逻辑运算符 && 使用时,会导致此诊断:
if ((c = getchar()) != EOF & c != ’0’) |