C 语言无符号与有符号整型溢出的区别

无符号整型溢出

对于无符号整型溢出,在 C 的规范中这是有定义的行为,溢出后的数会以 2^(8 * sizeof(type)) 作模运算,也就是说,如果一个无符号字符型(1 字节,8 位)溢出了,会把溢出的值与 256 求模。

1
2
unsigned char x = 0xff; // 1111 1111
printf("%d\n", ++x); // 结果为:0

有符号整型溢出

对于有符号整型的溢出,C 的规范定义是 Undefined Behavior,也就是说,编译器爱怎么实现就怎么实现。对于大多数编译器来说,算得啥就是啥。

注意:用补码表示。

1
2
3
signed char x = 0x7f;  // 0111 1111 表示最大的正数
// 0xff就是 -1 了,因为最高位是 1 也就是负数了
printf("%d\n", ++x); // -128

数据表示示意图(逆时针看)

++x 的结果为 1000 0000,因为这是补码,所以值为 -128

所以,有符号整型的溢出规律 一般 呈环形变化。

如果还是觉得不能理解可以看一下补码的表示方法:关于补码的总结

整型溢出可能导致死循环

1
2
3
4
5
6
#define MAX_LEN 32767
short len = 0;

while (len < MAX_LEN) {
len += 2;
}

short 是 2 字节长的有符号整型类型,能表示 -32768 ~ 32767 范围内的整数。当 len 的值为 32766 时,加 2 运算使得其溢出,值为 -32768,而不是 32768,如此不断循环。加 1 不会出现这样的问题,当 len 为 32767 时,循环将会终止。