C整型与整型溢出

本文详细探讨了C语言整型数据类型的特点,包括位宽、符号和取值范围,以及原码、反码和补码的概念。讨论了整型溢出的原因,如宽度和符号问题导致的溢出,并提供了避免整型溢出的建议。
摘要由CSDN通过智能技术生成

0 摘要

本文以表格的形式讨论了C语言整型数据类型的特点,以及原码、反码、补码和整型取值范围的关系;基于对整型取值范围的认识,对整型溢出的原因做了一个大致分类,也从汇编的层面去探讨了整型“下溢”的本质。

1 整型数据类型

整型数据类型是C语言中的一种基本类型,其存储的是整数,可分为两大类:有符号整型和无符号整型。

1.1 位宽、符号和取值范围

各整型类型的位宽及取值范围如下表所示。

类型 位宽 最小值 最大值
char 8 -128 127
unsigned char 8 0 255
short 16 -32 768 32 767
unsigned short 16 0 65 535
int 32 -2 147 483 648 2 147 483 647
unsigned int 32 0 4 294 967 295
long 32 -2 147 483 648 2 147 483 647
unsigned long 32 0 4 294 967 295
long long 64 -9 223 372 036 854 775 808 9 223 372 036 854 775 807
unsigned long long 64 0 18 446 744 073 709 551 615
  • 位宽
    不同的整型类型,有不同的位宽。需要注意的是,不同环境下某些整型类型的位宽定义可能不一样,比如64位Ubuntu17.10+GCC7.2.0编译器的long和64位win7+VS2010的long位宽不一样。16位系统的int和32位系统的int位宽不一样。具体位宽可以通过sizeof()来获知。

  • 符号
    无符号整型和有符号整型在编码上的区别在于“符号位”的有无。下图以8位的整型为例,有符号整型的最高位用作符号位,其余位用来表示数值的绝对值,符号位为1代表这是一个负数,为0表示正数。而无符号数没有符号位,整个内存区间都用来表示数值大小。
    在这里插入图片描述

  • 取值范围
    符号位的有无和位宽的大小决定了整型数据的取值范围。对于位宽为n的无符号整型,其取值范围为:[0, 2n-1],这是显而易见的。对于位宽为n的有符号整型,其取值范围为:[-2n-1, 2n-1-1],为什么是这样的取值范围,后面讨论。

1.2 原码、反码和补码

下面的表格是正数、负数以及一些具体数值的原码、反码和补码的关系示意。表格第三列中的符号“~”和第四列中的符号“>>”分别代表“按位取反”和“右移”,跟C语言里的定义一样。

十进制 原码 反码 补码 右移操作
正数 符号位 = 0 = 原码 = 反码
= 原码
= ~负数补码 + 1
最高位补0
负数 符号位 = 1 符号位不变,
其余各位取反
= 反码 + 1
= ~正数补码 + 1
最高位补1
4 0000 0100 0000 0100 0000 0100 4 >> 1 = 0000 0010补码 = 2
-4 1000 0100 1111 1011 1111 1100 -4 >> 1 = 1111 1110补码 = -2
1 0000 0001 0000 0001 0000 0001 1 >> 1 = 0000 0000补码 = 0
-1 1000 0001 1111 1110 1111 1111 -1 >> 1 = 1111 1111补码 = -1
  • 原码
    原码就是“最高位表示符号,其余位表示数值的绝对值”的编码。

  • 反码
    相对原码而言,正数的编码不变,负数的编码除符号位外所有位都按位取反,就是反码。

  • 补码
    相对反码而言,正数的编码不变,负数的编码加1,就是补码。这是计算机存储数值的编码方式。

1.3 再论有符号数取值范围

前面说到,位宽为n的有符号整型,其取值范围为:[-2n-1, 2n-1-1]。以char型为例,则其取值范围为[-128, 127]。为什么取值范围是[-128, 127],而不是[-127, 128]呢?

我们知道原码非常直观而容易理解,但是这种编码在计算机上进行运算是比较复杂的——需要先判断正负,再进行加减。相比之下,反码的运算则比较简单,因为反码让符号位也参与了运算(省去了符号位的判断),让减法可以用加法来表示(省去了专门的减法电路),比如4-4,可以表示为4+(-4),即0000 0100反码+1111 1011反码=1111 1111反码=1000 0000原码=0

但反码有个问题:由于0的原码有两个:“正零”00000000原码和“负零”10000000原码,导致反码也有两个0:“正零”00000000反码和“负零”11111111反码

如下表所示,原码和反码的“零”都有两种编码。

十进制 原码 反码
-127 1111 1111 1000 0000
-126 1111 1110 1000 0001
-2 1000 0010 1111 1101
  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值