关于C之整型溢出后的值

mac2026-03-03  5

#include <stdio.h> int main(void) { int i = 2147483647; // maximum value of int unsigned int j = 4294967295; // maximum value of unsigned int printf("%d %d %d\n", i, i+1, i+2); printf("%u %u %u\n", j, j+1, j+2); return 0; } 2147483647 -2147483648 -2147483647 4294967295 0 1

对于第一条输出,maximum+1后,刚好溢出,想像一下maximum的二进制表示就可以知道。

maximum的二进制表示为32位(1个0加32个1,由于是signed int,首位是符号位):01111111111111111111111111111111

这时+1,可想而知是unsigned int类型最大的负数值,即-(maximum+1)=-2147483648

对于第二条输出,由于maximum是unsigned int的二进制表示为32个1,即:11111111111111111111111111111111

这时+1,变为1后面加32个0,多出的高位都截掉,就剩下32个0了,即溢出后的值为0

为什么如下的代码不对?

int a = 1000, b = 1000; long int c = a * b;

因为根据C的整型提升规则,乘法是用int进行的,而其结果可能会在提升或赋值给左边的long int型之前溢出或被截短。 


#include <stdio.h> int main(void) { unsigned int un = 3000000000; long big = 65537; printf("un = %u and not %d\n", un, un); printf("big = %ld and not %hd\n", big, big); // %h->short return 0; } un = 3000000000 and not -1294967296 big = 65537 and not 1

以上是直接打印,由于故意设置了不兼容的打印格式(在IDE上会有Warning!),所以打印出的数值与原可能的预期不符,对于这种转换上的溢出,其实是丢失了高位,取低位的值。以long big=65537为例,它占4字节32位,它的二进制表示: 0000 0000 0000 0000 0001 0000 0000 0000 0001。而short 占用内存空间2个字节,也就是16个二进制位。这时截取低16位,所以得:0000 0000 0000 0001 = 1。由于int也是占4个字节32位,所以换成%d打印,结果也是对的。对于unsigned in un而言,道理是一样的。

由于C中int与char是一样的,只是一个占4byte,一个占1byte,下图展示了int转char时高位截掉取低8位的情况:

所以printf("%c",336);得出的结果是字符'P'。

总则:溢出后取低位。

可参见:关于整数与浮点数二进制表示,获取更多相关知识。

最新回复(0)