C——整数溢出
短的整数类型赋值给长的整数类型
-
示例代码
void main() { int w = 0x12345678; unsigned short r = -2; w = r; printf("%d\n", w); getchar(); }
-
上面结果最后是,65534,这是无符号的,如果是有符号呢?结果是,-2,这里的过程如下
- 无符号 short 后面挂了一个负数,显示是超过了范围,但是从语法上是不会报错的,那么在内存中又是怎么存储 -2呢
- 依然按照有符号的方式存储 -2,最高位是符号位,数值1, 因为是负数,那么存储是按照补码方式存储,结果是,1111 1111 1111 1110
- 赋值操作是整个替换,int 类型后面 16位被 1111 1111 1111 1110 占据,前面 16位会按照 short 类型判断,进行填充,因为此时 short 是无符号类型,所以 int 不会管 short 最高位是1还是0,前16位全部补充0
- 0000 0000 0000 0000 1111 1111 1111 1110,这是最后内存的形式
- printf 参数 %d,是按照 int 类型的有符号方式输出成十进制的数,所以它认为上面的结果是正数,所以其源码和补码一致,不用进行转化,结果输出,65534
- 下面说有符号的时候的为什么输出结果是 -2,内存将 -2 按照补码进行存储,也就是,1111 1111 1111 1110
- 赋值给 int 类型的时候,它依然会判断 short 类型,因为是 short 是有符号类型,它会根据 short 符号位填充自己的前16位,如果short 符号位是1,那么前16位都会是1,所以结果是,1111 1111 1111 1111 1111 1111 1111 1110
- printf 参数是 %d,它会依据有符号 int 类型方式输出成十进制的数,所以判断上述结果符号位,结果是1,需要将补码再次转成源码(与转补码过程一致),结果是 1000 0000 0000 0000 0000 0000 0000 0010,最后结果是 -2
长的整数类型赋值给短的整数类型
-
示例代码
void main() { int w = 0x12349678; unsigned short r = 1; r = w; printf("%d\n", r); getchar(); }
-
上面结果最后是 ,38520,这是无符号,那么如果是有符号呢?结果是,-27016,换了符号结果的变化过程如下
- 0x12345678,是一个正数,所以在内存中它的补码就是它的原码,00001 0010 0011 0100 1001 0110 0111 1000
- short 类型长度就是2个字节,所以它能获取到的数值就是 9678,继承来的补码为,1001 0110 0111 1000
- printf 参数是 %d,其含义是输出有符号的 int 类型的十进制数值,所以需要将 short 类型往前填充16位,这个过程与上面 short类型赋值给 int 过程是一致,先判断 short 是否有符号,无符号直接填充16个0,又因为是正数,所以不用再次转码,所以最后输出是 ,38520
- 那么有符号的为什么是,-27016呢,原因还是 printf 后面补位的原因,因为此时 short 是有符号的,又由于 short 符号位是1,那么前16位都会是1 ,1111 1111 1111 1111 1001 0110 0111 1000 ,又因为是负数,所以还需要转码,那么最后二进制转码之后是,1000 0000 0000 0000 0110 1001 1000 1000,所以最后是 ,-27016
最后的关于 short、int 一些总结
-
示例代码
void main() { unsigned short num = -2; printf("%d", num); getchar(); }
-
有无符号对输出结果的影响是很明显的 ,上面的结果无符号是,65534,有符号是,-2,
-
主要原因是补位过程,会根据数据类型,来进行补位,如果是 unsigned 修饰,那么直接不用判断,直接补0,如果没有 unsigned 修饰,才去判断具体数的符号位,如果是1,就直接补16个1,如果是0,则还是补16个0