长话短说,当你有以下情况时会发生这种情况:
unsigned char n = 255; /* highest possible value for an unsigned char */
n = n + 1; /* now n is "overflowing" (although the terminology is not correct) to 0 */
printf("overflow: 255 + 1 = %u\n", n);
n = n - 1; /* n will now "underflow" from 0 to 255; */
printf("underflow: 0 - 1 = %u\n", n);
n *= 2; /* n will now be (255 * 2) % 256 = 254;
/* when the result is too high, modulo with 2 to the power of 8 is used */
/* for an 8 bit variable such as unsigned char; */
printf("large overflow: 255 * 2 = %u\n", n);
n = n * (-2) + 100; /* n should now be -408 which is 104 in terms of unsigned char. */
/* (Logic is this: 408 % 256 = 152; 256 - 152 = 104) */
printf("large underflow: 255 * 2 = %u\n", n);
结果是(使用 gcc 11.1 编译,标志 -Wall -Wextra -std=c99):
overflow: 255 + 1 = 0
underflow: 0 - 1 = 255
large overflow: 255 * 2 = 254
large underflow: 255 * 2 = 104
现在是科学版本:上面的 cmets 仅代表正在发生的事情的数学模型。为了更好地了解实际发生的情况,以下规则适用:
- 整数提升:
小于 int 的整数类型在操作时被提升
对他们进行。如果原始类型的所有值都可以
表示为 int,较小类型的值转换为
一个整数;否则,将其转换为无符号整数。
所以当计算机执行n = 255; n = n + 1; 时,内存中实际发生的情况是:
首先,右侧被评估为一个 int(有符号),因为根据整数提升的规则,结果适合一个有符号的 int。所以表达式的右边变成了二进制:0b00000000000000000000000011111111 + 0b00000000000000000000000000000001 = 0b00000000000000000000000100000000(一个 32 位整数)。
- 截断
32 位 int 在分配时丢失了最高有效的 24 位
返回一个 8 位数字。
所以,当0b00000000000000000000000100000000被赋值给变量n时,它是一个无符号字符,32位值被截断为8位值(只复制最右边的8位)=> n变成@ 987654326@.
每个操作都会发生同样的事情。右侧的表达式计算为有符号整数,而不是被截断为 8 位。