栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

一分钟带你了解C语言中数据在内存中的存储详解!

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一分钟带你了解C语言中数据在内存中的存储详解!

引文:C语言中数据(整形/浮点型)在内存中都是以二进制的形式进行存储的

目录

C语言-整形数据在内存中存储

1:整形数据的二进制表示形式

2:整形数据在内存中是以补码的形式存储的

3:经典例题

C语言-浮点型数据在内存中存储

1:IEEE754规定1

 2:IEEE754规定2

 3:特殊浮点型数据存储

4:浮点型数据存储经典例题



C语言-整形数据在内存中存储

1:整形数据的二进制表示形式

1.1  概念:C语言中整形数据的二进制表示形式有三种,也就是我们计算机原理中学习到的原码、反码、补码。

附加:三种表示形式均有符号位和数值位两部分,最高位为符号位,符号位都是用0表示“正”,用1表示“负”,而剩余的bit位为数值位。

附加:整形数据包含了以下类型:

 附加:字符型char在划分的时候,也属于整形,因为char类型在底层是用ASCLL表示的,而ASCLL也属于整形

1.2  正整数

原码:直接将数据按照正负数的形式翻译出来的二进制值

反码:同原码

补码:同原码

结论:正整数的三种二进制值表现形式:原码 <==> 反码 <==> 补码

示例:

备注:数据10是正整数,所以最高位符号位为0, 因为10在vs2019编译器中默认推导的值属性是int,所以占用内存空间的大小是4byte即32bit,所以得到除符号位0以外剩下的31位为数据位。

1.3  负整数

原码:直接将数据按照正负数的形式翻译出来的二进制值

反码:最高位符号位不变,剩下的数据位全部按位取反

补码:最高位符号位不变,将反码取反后的值+1

示例:

 备注:数据-10是负整数,所以最高位符号位为1。

2:整形数据在内存中是以补码的形式存储的

通过vs编译器中的监视器查看

示例:

 备注:在main函数中定义了一个变量i,所以会在栈区上开辟对应大小的空间分配给main函数,然后在给main函数分配的空间里选择合适连续4字节空间分配给变量i,如上所示,地址0x0055F8F8~0x0055F8FB这4个内存单元就分配给了变量i(0x0055F8F8叫做内存单元的编号,也叫做地址,也可以理解成指针,每个内存单元的大小是1个字节)。而我们4个内存单元中存储的f6, ff, ff, ff其实就是将-10的补码二进制值写成十六进制的形式。拆分开来就是:

1111 0110 1111 1111 1111 1111 1111 1111

引申问题1:会发生我们从内存中读取出来的二进制值和我们直接写出的补码二进制值,好像是反着的。这里面就要谈到不同的编译环境或者说计算机系统中大小端的存储。

大端存储:数据的高位存放在内存中的低地址,数据的低位存放在内存中的高地址

小端存储:数据的低位存放在内存中的低地址,数据的高位存放在内存中的高地址

因为我自己计算机上是小端存储,所以,对于数据-10,补码二进制值是

1111 1111 1111 1111 1111 1111 1111 0110 <==>十六进制 ff ff ff f6

数据的低位是f6, 放到内存中的低地址 也就是0x0055F8F8, 从右往左以此类推,数据的高位是最左边的ff,存放到内存中的高地址 0x0055F8FB。

引申问题2:为什么整形数据在内存中存储的是补码

原因

1:使用补码,可以将符号位和数值域统一处理

2:加法和减法也可以统一处理(CPU只有加法器, 如 2-1 在CPU就是看成 2 + (-1)处理)

图解:

3:补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。(原码转换成补码需要经历取反和+1的操作,而补码转换成原码也只要取反和+1就可以得到原码 )

3:经典例题

 

 

 

 

 

 

C语言-浮点型数据在内存中存储

引文:C语言中浮点型数据按照IEEE754规定的存储规则以二进制的形式存储在内存中

1:IEEE754规定1

 示例:

 2:IEEE754规定2

针对有效数据M补充:

1:不管是32位浮点型还是64位浮点型,M一定是满足, 1<= M < 2, 所以为了能存储更高的精度,在存储的时候不存储M中整数部分,只存储小数部分,如1.xxxxx,在存入内存的时候,只存储xxxxx部分,从内存取出的时候,在自动加上1和小数点

针对指数E补充: 

1:当E不为全0或者全1的时候, 因为在存入内存的时候,会把E当成一个无符号整形看待,也就是对于32位浮点型数据,E的范围是0~255, 对于64位浮点型数据,E的范围是0~2047, 但是作为指数E, 它是可能出现负数的,所以为了能达到存入的时候,作为一个无符号整形,取出的时候,能还原成对应的数值,则针对32位浮点型数据,在存入的时候,E需要加上127, 得到的值在存入内存中,而针对64位浮点型数据,在存入的时候,E需要加上1023, 得到的值在存入内存中。

2:当E为全0的时候, 可以反向推导出,实际E的有效值一定是-127,因为-127+127等于0, 只有这种情况下,在内存中存入的时候,才会是全0, 从另一方面,如果E是-127, 那么当我们从内存中取出数据的时候,假设M等于1.xxxx, 那么还原成IEEE754规定的形式,就相当于

1.xxxxx * 2 ^ -127, 2^-127会是一个无限接近0的数字,所以当发生上述情况的时候,我们在取出M的时候,不加上1, 而是直接加上0, 相当于(-1) ^ S *0.xxxxx * 2 ^-127, 其实针对浮点型数据,这个浮点型数据已经是可以看成是0看待了, 因为float和double的小数点后精度只有小数点后6位和15位,而2 ^ -127在还原成浮点型的时候,需要向左移动127位,这已经是超过float和double的精度范围了,其所能表示的范围全部是0了

3:当E为全1的时候, 可以反向推导出,实际E的有效值一定是128, 因为128+127等于255, 只有这种情况下,在内存中存入的时候,才会使全1, 从另一方面, 如果E是128, 即便M中存储在内存中的部分是全0, 那么还原成IEEE754规定的形式也会是 (-1) ^ S *1.0 * 2 ^ 128,这个数字最终将会是一个+-无穷大的数字。 

示例:

 3:特殊浮点型数据存储

引申问题:当浮点型数据小数部分不为0的情况下,如何存储?如5.5或者3.6875?

解决方法:当浮点型数据小数部分不为0的情况下,针对小数部分,采用的是乘2取整法, 一直乘到余数为0的情况下,结束,从上到下取到整数部分,即表示小数部分的二进制值,而对于一些无法乘到余数为0的情况,采用截断的方式,截断到取整位数达到11位就结束。

如下

例子:

 

4:浮点型数据存储经典例题

 解析:

1:第一个printf输出9,这个是毋庸置疑的,格式说明符是%d, 即以有符号十进制的形式输出变量n, 则会将n变量所在的内存单元中的值当成无符号十进制的形式输出到标准输出上。

2:浮点型指针变量pf中保存了整形变量n的地址,对pf进行解引用,指针类型决定了其解引用权限多大,因为float和int都是4个字节,所以,其解引用的权限也是4个字节,但是,格式说明符是%f, 表示以浮点型的格式输出,那么这个时候就需要将pf所指向内存空间中的二进制值当成浮点型数据去解读,即以IEEE754规定的形式从内存中取出数据,如下图所示

可以看到科学计数法计数是-127, 那么需要将二进制值左移127位,这个数字已经是一个非常接近0的数字, 再因为float精度是小数点后6位,实际上解读出来的数据0.000000

3:*pf = 9.0,因为pf指针解引用的权限是4个字节,所以将浮点型数据9.0存储到了pf所指向的内存单元中。也就是以IEEE754规定的方式将9.0存入内存。所以最后一个printf函数正常以%f的形式打印*pf得到结果9.000000这个是毋庸置疑的

4:但是对于整形变量n, 因为变量n的地址没有改变,即变量n所表示的内存单元还是原来的内存单元,所以,当以%d的形式打印变量n的时候,就是将变量n所对应的内存单元中的二进制值,以有符号十进制的形式打印到标准输出上,而此时变量n对应的内存单元的值如下所示

 所以读取的时候,读取到的内容是41 10 00 00, 通过计算而得到结果是1091567616。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1037700.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号