跳过导航链接 | |
退出打印视图 | |
Oracle Solaris Studio 12.3:C 用户指南 Oracle Solaris Studio 12.3 Information Library (简体中文) |
1990 ISO C 标准的补充材料 "Rationale" 部分出现以下信息:"QUIET CHANGE"。依赖于无符号保留算术转换的程序表现各异,可能没有错误消息。此更改被认为是委员会对当前的普遍实践做出的最重大更改。
本节研究此更改如何影响代码。
在《The C Programming Language》的第一版中,unsigned 准确地指定一种类型,没有 unsigned char、unsigned short 或 unsigned long。但在此后不久,大多数 C 编译器增加了这些类型。有些编译器未实现 unsigned long,但是包含了其他两种类型。自然地,当这些新类型与在表达式中其他类型混合时,实现为类型提升选择不同的规则。
在大多数 C 编译器中,使用更简单的规则,即无符号保留。需要展宽无符号类型时,其将展宽为无符号类型;当将无符号类型与有符号类型混合时,结果是有符号类型。
ISO C 指定的另一个规则称为“值保留”,其中结果类型取决于操作数类型的相对大小。当展宽 unsigned char 或 unsigned short 类型时,如果 int 的长度足以表示较短类型的所有值,则结果类型为 int。否则,结果类型为 unsigned int。对于大多数表达式,值保留规则产生较少意外的算术结果。
仅在转换或 ISO 模式下(-Xt 或 -Xs ),ISO C 编译器才会使用无符号的保留提升。在其他两种模式下(符合 (–Xc) 和 ISO (–Xa)),将使用值保留提升规则。
在以下代码中,假定 unsigned char 比 int 窄。
int f(void) { int i = -2; unsigned char uc = 1; return (i + uc) < 17; }
该代码导致编译器在您使用 -xtransition 选项时发出以下警告:
line 6: warning: semantics of "<" change in ISO C; use explicit cast
加法运算结果的类型为 int(值保留)或 unsigned int(无符号保留),但二者之间的位模式不会更改。在二进制补码机器上:
i: 111...110 (-2) + uc: 000...001 ( 1) =================== 111...111 (-1 or UINT_MAX)
这种位表示对应于 -1(对于 int)或 UINT_MAX(对于 unsigned int)。因此,如果结果的类型为 int,将使用有符号比较,并且小于测试为 true。如果结果的类型为 unsigned int,将使用无符号比较,并且小于测试为 false。
强制类型转换的加法用来指定这两种行为之中所期望的行为:
value preserving: (i + (int)uc) < 17 unsigned preserving: (i + (unsigned int)uc) < 17
由于不同的编译器对相同的代码选择不同的含义,因此该表达式存在歧义。强制类型转换的加法帮助阅读器并消除警告消息。
相同的位字段值的提升存在同样的情况。在 ISO C 中,如果 int 或 unsigned int 位字段中的位数小于 int 中的位数,则所提升的类型为 int;否则,所提升的类型为 unsigned int。在大多数较旧的 C 编译器中,对于显式无符号位字段,所提升的类型为 unsigned int,在其他情况下为 int。
强制类型转换的类似使用可以消除存在歧义的情况。
在以下代码中,假定 unsigned short 和 unsigned char 均比 int 短。
int f(void) { unsigned short us; unsigned char uc; return uc < us; }
在此示例中,两个自动变量会同时提升为 int 或 unsigned int,因此比较有时无符号,有时带符号。然而,由于两种选择的结果相同,因此 C 编译器并不向您发出警告。
与表达式一样,有些整型常量的类型规则已更改。在 K&R C 中,无后缀二进制常量仅在其值足以表示 int 时才具有类型 int。无后缀八进制或十六进制常量仅在其值足以表示 unsigned int 时才具有类型 int。否则,整型常量的类型为 long。有时,值用结果类型不足以表示。在 1990 ISO/IEC C 标准中,常量类型是以下列表中与值对应的第一个类型:
无后缀二进制:int、long、unsigned long
无后缀八进制或十六进制:int、unsigned int、long、unsigned long
U 后缀:unsigned int、unsigned long
L 后缀:long、unsigned long
UL 后缀: unsigned long
当您使用 -xtransition 选项时,对于其行为可能会根据所涉及常量的类型处理规则而更改的任何表达式,ISO C 编译器会向您发出警告。旧整形常量类型处理规则仅在转换模式下使用。ISO 和符合模式使用新规则。
在以下代码中,假定 int 为 16 位。
int f(void) { int i = 0; return i > 0xffff; }
由于十六进制常量的类型为 int(在二进制补码机器上,值为 –1)或 unsigned int(值为 65535),因此在 –Xs 和 -Xt 模式下比较为真,在 –Xa 和 –Xc 模式下比较为假。
同样,相应的强制类型转换澄清代码并禁止警告:
-Xt, -Xs modes: i > (int)0xffff -Xa, -Xc modes: i > (unsigned int)0xffff or i > 0xffffU