32 位的有符号整数的取值范围以及数值溢出

2023-11-18

short、int、long 是C语言中常用的三种整数类型,分别称为短整型、整型、长整型。在现代操作系统中,short、int、long 的长度分别是 2、4、4 或者 8,它们只能存储有限的数值,当数值过大或者过小时,超出的部分会被直接截掉,数值就不能正确存储了,我们将这种现象称为溢出(Overflow)。溢出的简单理解就是,向木桶里面倒入了过量的水,木桶盛不了了,水就流出来了。要想知道数值什么时候溢出,就得先知道各种整数类型的取值范围。

无符号数的取值范围

计算无符号数(unsigned 类型)的取值范围(或者说最大值和最小值)很容易,将内存中的所有位(Bit)都置为 1 就是最大值,都置为 0 就是最小值。以 unsigned char 类型为例,它的长度是 1,占用 8 位的内存,所有位都置为 1 时,它的值为 2 8 - 1 = 255,所有位都置为 0 时,它的值很显然为 0。由此可得,unsigned char 类型的取值范围是 0~255。 前面我们讲到,char 是一个字符类型,是用来存放字符的,但是它同时也是一个整数类型,也可以用来存放整数,请大家暂时先记住这一点,更多细节我们将在《 在C语言中使用英文字符 》一节中介绍。 有读者可能会对 unsigned char 的最大值有疑问,究竟是怎么计算出来的呢?下面我就讲解一下这个小技巧。将 unsigned char 的所有位都置为 1,它在内存中的表示形式为 1111 1111 ,最直接的计算方法就是: 2 0 + 2 1 + 2 2 + 2 3 + 2 4 + 2 5 + 2 6 + 2 7 = 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255 这种“按部就班”的计算方法虽然有效,但是比较麻烦,如果是 8 个字节的 long 类型,那足够你计算半个小时的了。我们不妨换一种思路,先给 1111 1111 加上 1,然后再减去 1,这样一增一减正好抵消掉,不会影响最终的值。给 1111 1111 加上 1 的计算过程为: 0B1111 1111 + 0B1 = 0B1 0000 0000 = 2 8 = 256 可以发现,1111 1111 加上 1  后需要向前进位(向第 9 位进位),剩下的 8 位都变成了 0,这样一来,只有第 9 位会影响到数值的计算,剩下的 8 位对数值都没有影响。第 9 位的权值计算起来非常容易,就是: 2 9-1 = 2 8 = 256 然后再减去 1: 2 8 - 1 = 256 - 1 = 255 加上 1 是为了便于计算,减去 1 是为了还原本来的值;当内存中所有的位都是 1 时,这种“凑整”的技巧非常实用。按照这种巧妙的方法,我们可以很容易地计算出所有无符号数的取值范围(括号内为假设的长度):   unsigned char unsigned short unsigned int(4字节) unsigned long(8字节) 最小值 最大值
0 0 0 0
28 - 1 = 255 216 - 1 = 65,535 ≈ 6.5万 232 - 1 = 4,294,967,295 ≈ 42亿 264 - 1 ≈ 1.84×1019

有符号数的取值范围

有符号数以补码的形式存储,计算取值范围也要从补码入手。我们以 char 类型为例,从下表中找出它的取值范围: 补码 反码 原码 值
1111 1111 1111 1110 1000 0001 -1
1111 1110 1111 1101 1000 0010 -2
1111 1101 1111 1100 1000 0011 -3
…… …… …… ……
1000 0011 1000 0010 1111 1101 -125
1000 0010 1000 0001 1111 1110 -126
1000 0001 1000 0000 1111 1111 -127
1000 0000 -- -- -128
0111 1111 0111 1111 0111 1111 127
0111 1110 0111 1110 0111 1110 126
0111 1101 0111 1101 0111 1101 125
…… …… …… ……
0000 0010 0000 0010 0000 0010 2
0000 0001 0000 0001 0000 0001 1
0000 0000 0000 0000 0000 0000 0
我们按照从大到小的顺序将补码罗列出来,很容易发现最大值和最小值。淡黄色背景的那一行是我要重点说明的。如果按照传统的由补码计算原码的方法,那么 1000 0000 是无法计算的,因为计算反码时要减去 1,1000 0000 需要向高位借位,而高位是符号位,不能借出去,所以这就很矛盾。是不是该把 1000 0000 作为无效的补码直接丢弃呢?然而,作为无效值就不如作为特殊值,这样还能多存储一个数字。计算机规定,1000 0000 这个特殊的补码就表示 -128。为什么偏偏是 -128 而不是其它的数字呢?首先,-128 使得 char 类型的取值范围保持连贯,中间没有“空隙”。其次,我们再按照“传统”的方法计算一下 -128 的补码:
  • -128 的数值位的原码是 1000 0000,共八位,而 char 的数值位只有七位,所以最高位的 1 会覆盖符号位,数值位剩下 000 0000。最终,-128 的原码为 1000 0000。
  • 接着很容易计算出反码,为 1111 1111。
  • 反码转换为补码时,数值位要加上 1,变为 1000 0000,而 char 的数值位只有七位,所以最高位的 1 会再次覆盖符号位,数值位剩下 000 0000。最终求得的 -128 的补码是 1000 0000。
-128 从原码转换到补码的过程中,符号位被 1 覆盖了两次,而负数的符号位本来就是 1,被 1 覆盖多少次也不会影响到数字的符号。你看,虽然从 1000 0000 这个补码推算不出 -128,但是从 -128 却能推算出 1000 0000 这个补码,这么多么的奇妙,-128 这个特殊值选得恰到好处。负数在存储之前要先转换为补码,“从 -128 推算出补码 1000 0000”这一点非常重要,这意味着 -128 能够正确地转换为补码,或者说能够正确的存储。
关于零值和最小值
仔细观察上表可以发现,在 char 的取值范围内只有一个零值,没有 +0-0 的区别,并且多存储了一个特殊值,就是 -128,这也是采用补码的另外两个小小的优势。如果直接采用原码存储,那么 0000 00001000 0000 将分别表示 +0-0 ,这样在取值范围内就存在两个相同的值,多此一举。另外,虽然最大值没有变,仍然是 127,但是最小值却变了,只能存储到 -127,不能存储 -128 了,因为 -128 的原码为 1000 0000,这个位置已经被 -0 占用了。按照上面的方法,我们可以计算出所有有符号数的取值范围(括号内为假设的长度):   char short int(4个字节) long(8个字节) 最小值 最大值
-27 = -128 -215 = -32,768 ≈ -3.2万 -231 = -2,147,483,648 ≈ -21亿 -263 ≈ -9.22×1018
27 - 1= 127 215 - 1 = 32,767 ≈ 3.2万 231 - 1 = 2,147,483,647 ≈ 21亿 263 - 1≈ 9.22×1018
上节我们还留下了一个疑问, [1000 0000 …… 0000 0000]补 这个 int 类型的补码为什么对应的数值是 -2 31,有了本节对 char 类型的分析,相信聪明的你会举一反三,自己解开这个谜团。

数值溢出

char、short、int、long 的长度是有限的,当数值过大或者过小时,有限的几个字节就不能表示了,就会发生溢出。发生溢出时,输出结果往往会变得奇怪,请看下面的代码:
#include int main(){    unsigned int a = 0x100000000;    int b = 0xffffffff;    printf("a=%u, b=%d\n", a, b);    return 0;}
     
     
运行结果: a=0, b=-1变量 a 为 unsigned int 类型,长度为 4 个字节,能表示的最大值为 0xFFFFFFFF,而 0x100000000 = 0xFFFFFFFF + 1,占用33位,已超出 a 所能表示的最大值,所以发生了溢出,导致最高位的 1 被截去,剩下的 32 位都是0。也就是说,a 被存储到内存后就变成了 0,printf 从内存中读取到的也是 0。变量 b 是 int 类型的有符号数,在内存中以补码的形式存储。0xffffffff 的数值位的原码为 1111 1111 …… 1111 1111,共 32 位,而 int 类型的数值位只有 31 位,所以最高位的 1 会覆盖符号位,数值位只留下 31 个 1,所以 b 的原码为: 1111 1111 …… 1111 1111 这也是 b 在内存中的存储形式。当 printf 读取到 b 时,由于最高位是 1,所以会被判定为负数,要从补码转换为原码: [1111 1111 …… 1111 1111]
= [1111 1111 …… 1111 1110]
= [1000 0000 …… 0000 0001]
= -1 最终 b 的输出结果为 -1。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

32 位的有符号整数的取值范围以及数值溢出 的相关文章

  • CSS3背景渐变

    我们经常可以看到有些背景色并不是纯色 而是好看的渐变色 css3知我懂我 给我们提供了制作渐变背景色的属性 渐变主要包括线性渐变和径向渐变 接下来逐一介绍用法 1 线性渐变 线性渐变 linear gradients 表示颜色沿着一条直线过
  • 设计模式--原型模式

    原型模式 属于创建型模式 基本原理 又称为克隆模式 拷贝本身对象 可以直接使用语言中的拷贝构造 主要流程 在构建对象的时候实现一个对本身的拷贝函数 特别注意 要有对应的销毁方法 include
  • 集合框架(二)

    集合框架 二 回顾 Collection List Set的特点 Collection 不唯一的 无序的 List 不唯一的 有序 Set 唯一的 无序的 Collection和Collections的区别 Collection是集合的顶级
  • C语言/C++实现栈操作

    一 栈的概念 栈是一种常用的数据结构 它遵循先入后出 Last In First Out LIFO 的原则 栈的操作只在栈的一端进行 该端被称为栈顶 而另一端称为栈底 栈的基本操作包括压栈 入栈 push 和弹栈 出栈 pop 分别用于将元
  • HTTP 常见错误

    HTTP 错误 400 400 请求出错 由于语法格式有误 服务器无法理解此请求 不作修改 客户程序就无法重复此请求 HTTP 错误 401 401 1 未授权 登录失败 此错误表明传输给服务器的证书与登录服务器所需的证书不匹配 请与 We
  • 【Python与机器学习2-1】pandas 基本数据对象及操作

    series 相当于一维数组 要有向量化操作思想 series是类似一维数组的对象 即一个列向量 初始化series 通过列表初始化series 默认数字为索引 ser obj pandas Series list 通过字典初始化serie
  • JSP页面中page指令contentPage/pageEncoding具有什么功能呢?

    转自 JSP页面中page指令contentPage pageEncoding具有什么功能呢 下文将讲述page指令的contentPage及pageEncoding指令的功能简介说明 如下所示 page指令的contentPage及pag
  • Antd DatePicker 设置默认值报clone.weekday is not a function

    代码 dayjs版本1 11 7 页面 当点击页面日期框会报clone weekday is not a function 解决方法 在jsx文件中添加如下js import dayjs from dayjs import advanced
  • AngularJS单元测试环境搭建及验证

    AngularJS的单元测试 要测试AngularJS 需要先搭建相关的测试环境 之前已经安装了Node js并验证了基本的功能 同时下载了AngularJS的包 成功运行了AngularJS编写的程序 也就是说基本的开发环境已经构建完成
  • ArcGIS处理自相交面

    问题 我们在获取一些osm等开源地理数据网站获取数据后 比如建筑物数据 往往需要对数据进行处理后 才可以进行分析 对于面数据 处理面自相交问题是必须操作 如下图 就是自相交的面 解决方案 该问题可以使用ArcGIS轻松解决 新建线要素 选择
  • ARm 移植最新版QT5.12

    转载 https blog csdn net weixin 37771089 article details 84989447 一 准备 ubuntu 12 04 源码 http download qt io archive qt 5 12
  • IDEA使用maven进行多模块项目打包并梳理正确的打包顺序

    maven多模块打包一般相互之间都有互相的依赖关系 如果没有按照正确的依赖关系顺序进行打包就会报错 例如有三个模块web service common 其中web依赖service web和service都依赖common 那么正确的打包顺
  • hsql获取数组中最后一个值的写法

    一 问题抛出 在数据分析中我们有时候会遇到需要取出数组中最后一个值的方法 1 表xxx数据如下图所示 2 现在需要取出字符串最后的 321 和 987 二 方案探讨 1 反转字符串后 使用切割函数切割获取第一个值 然后再反转一下 代码如下
  • Spring Boot starter 启动流程(无废话版)

    如果无产阶级不能发出自己的声音 他们就会被社会遗忘 一 pom xml文件 1 父依赖 其中它主要是依赖一个父项目 主要是管理项目的资源过滤及插件
  • Superset整合keycloak系统

    本篇主要介绍superset如何整合单点登陆系统keycloak 现在网上的博客大部分都是失效了 这里我相当于更新一下 避免大家再走弯路 一 环境配置 Macos keycloak 18 0 0 superset 2 1 0 keycloa
  • PMSM学习笔记1——永磁同步电机的工作原理与数学模型

    文章目录 一 PMSM工作原理 1 同步电机工作原理 来源 电机学 李发海 2 永磁同步电机数学模型及坐标变换 来源 现代电机控制技术 王成元 2 1旋转磁场 2 2三相PMSM的基本数学模型 2 3三相PMSM的坐标变换 2 3 1 Cl
  • 【Unity 3D】学习笔记 - 粒子系统制作

    这次的任务是制作一个简单的粒子系统 并用代码控制使之在不同的场景下呈现出不同的效果 我想要制作出颜色渐变的烟花效果 关于粒子系统 可以参考 Unity 3D 学习笔记 粒子系统初探 粒子系统基本设置如下 其中Simulation Rotat
  • 学生用计算机怎么恢复出厂设置,电脑怎么恢复出厂设置

    关机或重启时 按住电脑键盘的 Del 键进入BIOS 使用Enter回车键选中 Load Optimized Defaults 选项 使用方向键选中 Y 确认 点击 Save Exit Step 或者按 F10 退出即可 以下是详细介绍 电
  • Go语言实现Onvif客户端:2、获取设备信息

    Go语言实现Onvif客户端 2 获取设备信息 文章目录 Go语言实现Onvif客户端 2 获取设备信息 1 思路 2 代码 1 思路 搜索设备 获取设备能力 通过设备能力的设备接口读取设备信息 我们上节说了 主要是通过设备信息中的内容来区
  • 线性代数 【基础1】

    文章目录 行列式 方阵的行列式公式 矩阵 矩阵的逆 矩阵的秩 伴随矩阵 初等变换与初等矩阵 分块矩阵 向量 正交矩阵 正交化 线性表示 线性无关与线性相关 极大无关组与向量组的秩 线性方程组 解的性质与判定 齐次线性方程组 非齐次线性方程组

随机推荐

  • 大型网站在架构上应当考虑哪些问题?

    分层 分层是处理任何复杂系统最常见的手段之一 将系统横向切分成若干个层面 每个层面只承担单一的职责 然后通过下层为上层提供的基础设施和服务以及上层对下层的调用来形成一个完整的复杂的系统 计算机网络的开放系统互联参考模型 OSI RM 和In
  • Java8 CompletableFuture处理多个异步任务

    CompletableFuture Java5引入了Future和 FutureTask 用于异步处理 Future可以通过get 方法获取异步的返回值 在Java8引入了CompletableFuture CompletableFutur
  • 设置GPU及显存大小

    20210128 引言 之前搜索过设置GPU和显存大小的方式 但是升级了新的版本的keras以及tensorflow 导致之前的代码失效了 这里记录一下 本质上 就是版本更换的原因 很多api可能被取消 或者改了别的 原始代码 import
  • 计算机网络ip尽最大努力交付,计算机网络知识(IP、TCP、UDP)--持续更新

    互联网的两个重要的基本特点 连通性和共享 计算机网络由若干结点和连接这些结点的链路组成 互联网的组成 边缘部分 核心部分 网络边缘的端系统之间的通信可分为两大类 客户 服务器方式 C S方式 和对等方式 P2P方式 互联网的核心部分 许多网
  • 原始传奇手游服务器不显示,原始传奇手游为什么进不去 无法登录游戏解决方法...

    近日有一款由古力娜扎代言的手游 原始传奇 上线了 不少玩家也很想体验一番 可是却发现原始传奇手游进不去 不知道是为什么 下面悠小悠就为大家详细介绍下无法登录游戏的原因和解决方法 一起探讨下吧 原始传奇手游进不去原因及解决方法 1 如果是登录
  • tomcat没有日志输出--解决办法

    程序没有问题 只是控制台信息卡 感觉像程序休眠了一样 然后在控制台点backspace或是enter 程序恢复正常 控制台日志正常输出 静态文件访问可以 解决办法 转载于 https blog 51cto com 13693838 2398
  • BIND9的架构与机制笔记1

    BIND9采用的是事件驱动的机制来工作 而事件的源头则是IO IO在linux使用的EPOLL的边缘触发模式 本篇说的是epoll BIND9如果创建了watcher线程 宏USE WATCHER THREAD控制 这里就讨论有线程的情况
  • Redis第五讲 Redis内存淘汰策略之LRU与LFU算法详细介绍

    前面介绍了Redis的一些内存淘汰策略 一般比较常用的两种淘汰策略为LRU LFU 而且他们的算法考察的也比较多 LRU 最近最久未使用 标准LRU算法是这样的 它把数据存放在链表中按照 最近访问 的顺序排列 当某个key被访问时就将此ke
  • 机器学习——无监督学习

    机器学习的分类 一般分为下面几种类别 监督学习 supervised Learning 无监督学习 Unsupervised Learning 强化学习 Reinforcement Learning 增强学习 半监督学习 Semi supe
  • Vue 中实现 excel文件上传功能

    Duang 最近搭建了一个自己的博客小破站 欢迎各位小伙伴来访吖 ares coder blog portalhttps www ares stack cn blog service game 场景 上传excel表 并将excel表中的数
  • Django实现前后端分离开发

    前后端分离开发 在传统的Web应用开发中 大多数的程序员会将浏览器作为前后端的分界线 将浏览器中为用户进行页面展示的部分称之为前端 而将运行在服务器 为前端提供业务逻辑和数据准备的所有代码统称为后端 所谓前后端分离的开发 就是前后端工程师约
  • Hadoop 之上的数据建模 - Data Vault 2.0

    对比传统的基于 RDBMS 之上的数据仓库和商业智能项目 尝试着说说 Hadoop 之上的数据仓库 从ETL 数据存储 到分析展现 重点围绕数据建模方面做分析 因为这是本文的重点 介绍一份新的数据建模方式 Data Vault 2 0 ET
  • HTML框架构建

    HTML框架构建 1 划分框架 A 使用标签决定如何划分框架 必须要有标签设定每个小窗口的网页 该标签中有src属性为每个URL值指定一个HTML文件 这个文件必须事先做好 B 标签常用的属性 属性 描述 cols 用 像素数 或 分个左右
  • Android-PullToRefresh下拉刷新库基本用法

    PullToRefresh是一套实现非常好的下拉刷新库 它支持 ListView ExpandableListView GridView WebView ScrollView HorizontalScrollView ViewPager 等
  • AutoEncoder (自编码/非监督学习)

    神经网络也能进行非监督学习 只需要训练数据 不需要标签数据 自编码就是这样一种形式 自编码能自动分类数据 而且也能嵌套在半监督学习的上面 用少量的有标签样本和大量的无标签样本学习 这次我们还用 MNIST 手写数字数据来压缩再解压图片 然后
  • Boost升压电路调试

    背景 项目用到了一款升压电路 将12V升压到32V 电流要求有12A 最大18A 设计的方案是使用Boost Controller 外置MOS来实现 选定的Controller芯片为Maxim的MAX25203 问题 回板后进行调试 在不使
  • 硕士毕业论文应该如何梳理论文框架?

    硕士毕业论文相比于本科论文来说 具有更为广阔的知识面 对于研究的课题也更有深度 如果硕士毕业论文能取得一个很高的成绩 那么不管之后是继续求学还是找工作 都会有一定的优势 我曾经就硕士论文这方面和我的一个同学讨论过 当时我询问他是怎么取得69
  • React+React-Redux+Webpack+Express+MongoDB完整项目利用PM2+github部署到服务器

    React项目使用pm2部署上线 简述 项目概述 项目文件和代码结构 登录到服务器 输入指令 安装和配置nginx 安装MongoDB 打通三端 客户端 github 服务器 本地到github 服务器到github 本地到服务器 pm2部
  • 正大讲解什么叫国际期货?需要多少本金?

    国际期货是指交易所建立在中国大陆以外的期货交易 以美国 英国 新加坡等交易所内的产品为常见交易期货合约 有些期货合约品种会对国内期货价格变动产生影响 所以国内投资者可以参考国际期货行情进行期货交易 开户没有资金限制 但交易期货要交纳手续费和
  • 32 位的有符号整数的取值范围以及数值溢出

    short int long 是C语言中常用的三种整数类型 分别称为短整型 整型 长整型 在现代操作系统中 short int long 的长度分别是 2 4 4 或者 8 它们只能存储有限的数值 当数值过大或者过小时 超出的部分会被直接截