【我为同学解难题| 第244期】C++第11期:数据溢出

文摘   2024-10-22 19:01   江苏  


在我们日常的C++编程中,基本的数值类型如int、short、char和unsigned非常常见的。然而,溢出(Overflow)的概念常常会让初学者感到困惑。实际上,当变量的值超过其类型的存储容量时,就会发生溢出。本篇文章将介绍溢出的基础知识,并以32位机器为例,解释C++中这些类型的溢出是如何发生的。



1 基本数据类型及其范围

在32位机器上,常用的数值数据类型如int、short和char的大小是固定的,它们能存储的值的范围也有限。首先,我们回顾一下这些常见类型的大小和数值范围:

int(有符号整数)

大   小:4字节(32位)

范围:-2,147,483,648到 2,147,483,647

unsigned int(无符号整数)

大小:4字节(32位)

范围:0 到 4,294,967,295

short(有符号短整数)

大小:2字节(16位)

范围:-32,768 到 32,767

unsigned short(无符号短整数)

大小:2字节(16位)

范围:0 到 65,535

char(有符号字符)

大小:1字节(8位)

范围:-128 到 127

unsigned char(无符号字符)

大小:1字节(8位)

范围:0 到 255


2 什么是溢出?

当你试图存储一个超出某个数据类型有效范围的值时,就会发生溢出。当溢出发生时,值会“绕回”到该类型允许范围的另一端,这可能会导致意想不到的结果。

溢出有两种类型:

有符号溢出:发生在有符号类型,如int、short或char。

无符号溢出:发生在无符号类型,如unsigned int或unsigned char。

以short类型为例,它在32位机器上的范围是 -32,768 到32,767。如果你在最大值32,767上加1,结果将“绕回”到最小值 -32,768。

图1 short类型变量正溢出示例

这种行为的原因是变量已经没有足够的空间来存储新值,二进制表示“绕回”到了范围的另一端。

对于unsigned short,其范围是0到65,535。如果你从0中减去1,结果会绕回到65,535。

图2 short类型变量负溢出示例

无符号类型从不具有负值,因此当最小值(0)在负方向上被超过时,它会绕回到该类型的最大值。


3 为什么会发生溢出?

溢出的根本原因在于数据在内存中的存储方式。像int或short这样的数据类型有固定的位数。当一个值超过这些位所能表示的最大容量时,位就会“滚动”,值就会绕回。

为了深入理解溢出,我们需要从底层的二进制表示和计算的角度来解释。为了便于解释,下面以short为例进行详细的阐释。

short类型一般使用16位(2 字节)存储,使用补码表示。其最大值是32,767,二进制补码表示为0111 1111 1111 1111。此时如果再加1,此时结果是1000 0000 0000 0000,即补码表示法中的-32768。这意味着一旦加1超过了short类型的最大值,数值就会“绕回”到最小值。这就是所谓的正溢出。

类似的,负溢出发生在数值小于short类型的最小值 -32,768 时。如果我们从-32,768再减 1,会发生溢出,结果绕回到 32767。

unsigned类型也是如此,以unsigned short为例,unsigned short最大值为655,35,二进制表示为1111 1111 1111 1111,加1之后,结果其实应该是1 0000 0000 0000 0000。但是,溢出时,高位的进位被丢弃,计算机并不关心超出的部分,只保留有限的位数。因此,最终的结果只会是0000 0000 0000 0000。

4 溢出的计算方法

基于数据溢出的底层原理,我们可以归纳一套计算溢出的方法。

首先,需要计算数据范围跨度,数据范围跨度 = 最大值 - 最小值+1。例如,short的数据范围跨度为32,767- (-32,768)+1 =65,536。

对于有符号类型,当溢出的数据为正数时,计算方式为:最小值+溢出值 % 数据范围跨度-1。

对于char 类型的变量a,若有赋值语句a=129,则利用上述计算方式,溢出值为1,1%256 =1。最终的存储值为-128 +1-1=129。

换个复杂的例子,对于char类型的变量b,若有赋值语句b= 500,则利用上述计算方式,溢出值为373,373%256 =117,而-128+117-1=-12,最终的存储值为-12。

同样对有符号类型,当溢出的数据为负数时,计算方式为:最大值-溢出值%数据范围跨度+1。

对于char类型的变量a,若有赋值语句a=-129,则利用上述计算方式,溢出值为1,1%256 = 1。最终的存储值为127- 1+1=129。

对于char类型的变量b,若有赋值语句a=-500,则利用上述计算方式,溢出值为372,372%256 =116。最终的存储值为 127-116+1=12。

对于char类型的变量a,若有赋值语句a=-128,则利用上述计算方式,计算可得-128+256=-127。-127就是计算机最终存储的结果。

无符号类型的溢出处理较为简单。超出最大值时,直接进行模运算并取结果。

unsigned short 类型的范围是0到65535,当i=70000 时,进行模运算:70000%65536 =4464,因此,i=4464。

若如果无符号类型的负值数值为负数,则逐次加数据范围跨度,直至为正值则为最终结果。

例如,当i=-30000时,直接加上65536,即可得到答案35536。

 

学习到这里辛苦啦!不过在这里还是想考察一下大家知识点的掌握水平,下面是一道例题哦!

若有unsigned short a=-1,b=100;,执行完语句(a<b)&&(++a);< span="">后a的值为:

    A) -1         B)0   

    C) 65535   D)65536

答案:C

解析:

当a=-1时,由于unsigned short是无符号类型,负数会进行模65536的运算。通俗地来说,就是我们上面提到的“逐次加数据范围跨度,直至为正值则为最终结果”。-1等价于-1+65536 = 65535,因此a=65535。

接下来看看后面的表达式,这是一个逻辑与运算,整个表达式可以分为两部分来处理:由于65535大于100,因此(a<b)的结果是false。逻辑与运算中,左侧的表达式已经是false,根据短路求值原则,右侧的++a不会执行。因此,a的值保持不变,仍然是65535。





策 划 | 本科生学业指导中心
图 文 | 朱欣宇

编 辑 | 汪    昊
初 审 | 官子涵

复 审 | 陈祚瑜

审 核 | 尚文浩

推荐阅读








微言新语㊺ | 郝海玲:筑牢理想信念根基,提升价值引领能力


筑梦领航,智胜考研|设计艺术与传媒学院开展“学霸开讲”活动

以梦为马,不负韶华|2024-2025学年校级学导团队介绍

南理工学生事务微平台
南京理工大学学生工作处设立,面向我校全体本科生,推送校园新闻,开设专题报道,建立沟通渠道,提供实用服务,欢迎添加关注!
 最新文章