在 C 中,自动类型转换遵循 "通常算术转换" 的原则。当表达式中有不同符号(有符号/无符号)的数字参与时,转换的规则如下:
危险的算术示例:
int a = -1; // 有符号 unsigned int b = 1; printf("%d ", a < b); // 始终为 false,因为 a 转换为一个非常大的无符号数
结果:-1 在转换为无符号数后,会变成一个非常大的正数。
重要需要记住的事项:
问题: 表达式 (int)(unsigned)-1 会返回什么结果?
预期错误答案: "-1,因为 -1 会转换为 int。"
正确答案:
在表达式 (unsigned)-1 中,首先将 -1 转换为无符号数(在32位平台上是 0xFFFFFFFF),然后再转换回有符号 int,这也依赖于实现,但通常会再次得到 -1(如果使用二进制补码)。然而,更准确地说:结果依赖于有符号数的表示标准,但在大多数实现中将会得到 -1。
示例:
int x = (int)(unsigned)-1; // x == -1 在大多数平台上
历史
在字符串处理程序中使用了大小比较函数:如果字符串的长度可能为负,那么程序就会报告错误。然而,长度是 size_t(无符号类型),比较代码
if(length < 0)始终为 false,导致无限循环和内存溢出。
历史
在解析协议时,网络包中字段为无符号类型,而局部变量为有符号类型。由于处理某些值时无符号溢出,导致包长度计算不正确,这导致了缓冲区溢出的漏洞。
历史
日志中的日期比较模块将日期存储为无符号 int,寻求的日期范围为 int。一些边界值未能如预期那样引发异常,导致记录过滤不正确并丢失重要日志。