第18讲:数据在内存中的存储

⽬录
1. 整数在内存中的存储
2. ⼤⼩端字节序和字节序判断
3. 浮点数在内存中的存储
———————————————————————————————————————————

1. 整数在内存中的存储  

在讲解操作符的时候,我们就讲过了下⾯的内容:
整数的2进制表⽰⽅法有三种,即 原码、反码和补码
有符号的整数,三种表⽰⽅法均有符号位数值位两部分,符号位都是⽤0表⽰“正”,⽤1表
⽰“负”,最⾼位的⼀位是被当做符号位,剩余的都是数值位。
正整数的原、反、补码都相同。
负整数的三种表⽰⽅法各不相同。
原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码。
对于整形来说:数据存放内存中其实存放的是补码。
为什么呢?
在计算机系统中,数值⼀律⽤补码来表⽰和存储。
原因在于,使⽤补码,可以将符号位和数值域统⼀处理;
同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

2. ⼤⼩端字节序和字节序判断 

当我们了解了整数在内存中存储后,我们调试看⼀个细节:
#include <stdio.h>

int main()
{
int a = 0x11223344;
 
return 0;
}
调试的时候,我们可以看到在a中的 0x11223344 这个数字是按照字节为单位,倒着存储的。这是为什么呢?

2.1 什么是⼤⼩端?

其实超过⼀个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为⼤端字节序存储和⼩端字节序存储,下⾯是具体的概念:
⼤端(存储)模式:
是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处。

⼩端(存储)模式:

是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。 

例如10进制中的123,1、2、3分别是百位,十位,个位,那么3就是低位。 

上述概念需要记住,⽅便分辨⼤⼩端。

2.2 为什么有⼤⼩端?

为什么会有⼤⼩端模式之分呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit 位,但是在C语⾔中除了8 bit 的 char 之外,还有16 bit 的 short 型,32 bit 的 long 型(要看
具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。
例如:⼀个 16bit short x ,在内存中的地址为 0x0010 x 的值为 0x1122 ,那么0x11 为⾼字节, 0x22 为低字节。对于⼤端模式,就将 0x11 放在低地址中,即 0x0010 中,0x22 放在⾼地址中,即 0x0011 中。⼩端模式,刚好相反。我们常⽤的 X86 结构是⼩端模式,⽽KEIL C51 则为⼤端模式。很多的ARM,DSP都为⼩端模式。有些ARM处理器还可以由硬件来选择是⼤端模式还是⼩端模式。

2.3 练习

2.3.1 练习1  

请简述⼤端字节序和⼩端字节序的概念,设计⼀个⼩程序来判断当前机器的字节序。(10分)-百度笔试题
//代码1
#include <stdio.h>
int check_sys()
{
 int i = 1;
 return (*(char *)&i);
}
int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("⼩端\n");
 }
 else
 {
 printf("⼤端\n");
 }
 return 0;
}

解题思路:这里将&i的int*地址强制转化为(char*),而不是将int强制转化为char。

2.3.2 练习2

#include <stdio.h>
int main()
{
 char a= -1;
 signed char b=-1;
 unsigned char c=-1;
 printf("a=%d,b=%d,c=%d",a,b,c);
 return 0;
}

无论是否有无符号位,存入内存的都是补码,11111111,至于打印出来是什么,这时候就与signed、unsigned有关了。

%d意思就是我以有符号数的形式打印

a、b:char类型的要以%d的形式打印,需要整型提升,有符号位,那就补符号位变为11111111 11111111 11111111 11111111

补码转化为原码就是1000000...0001:-1

c:无符号位,整型提升补充0,00000....11111111,正数,原反补相同,打印结果为255

2.3.3 练习3

#include <stdio.h>
int main()
{
 char a = -128;
 printf("%u\n",a);
 return 0;
}

这里char a = -128意思是以8个比特位的方式存储a的补码,多余的比特位不要,所以存入的是10000000,打印的时候是以%u(%u认为打印的为无符号数int,%d认为是有符号数int),先对a进行整型提升,看a的类型是char,有符号位的char,10000000的高位是符号位1,所以补符号位1,之后再打印时打印的是无符号位,打印结果为11111111 11111111  11111111 10000000的10进制

2.3.4 练习4

#include <stdio.h>
int main()
{
 char a[1000];
 int i;
 for(i=0; i<1000; i++)
 {
 a[i] = -1-i;
 }
 printf("%d",strlen(a));
 return 0;
}

for循环对数组进行赋值,-1,-2...-128,由于char是有符号位,其范围为-128~127,接下来会存储

127,126.。。。

strlen求得是字符串的长度,统计的是\0(ASCII码值是0)之前的字符个数,当循环了一个周期后,输出255。

2.3.5 练习5

#include <stdio.h>
unsigned char i = 0;
int main()
{
 for(i = 0;i<=255;i++)
 {
 printf("hello world\n");
 }
 return 0;
}

由于unsigned char类型最多储存255个,到达255后又会回到0,所以永远满足i<=255,会死循环的打印

3. 浮点数在内存中的存储

常⻅的浮点数:3.14159、1E10等,浮点数家族包括: float double long double 类型。
浮点数表⽰的范围: float.h 中定义

3.1 练习

#include <stdio.h>
int main()
{
 int n = 9;
 float *pFloat = (float *)&n;
 printf("n的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 *pFloat = 9.0;
 printf("num的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 return 0;
}

3.2 浮点数的存储

上⾯的代码中, num *pFloat 在内存中明明是同⼀个数,为什么浮点数和整数的解读结果会差别这么⼤?
要理解这个结果,⼀定要搞懂浮点数在计算机内部的表⽰⽅法。
根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
V   =  (−1) ^ M ∗ 2^ E
(−1) S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
M 表⽰有效数字,M是⼤于等于1,⼩于2的
2 E 表⽰指数位
举例来说:
⼗进制的5.0,相当于5.0×10^0。写成⼆进制是 101.0 ,相当于 1.01×2^2
那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2。
⼗进制的-5.0,写成⼆进制是 -101.0 ,相当于 -1.01×2^2 。那么,S=1,M=1.01,E=2。
十进制的0.5,相当于5.0×10^-1。写成二进制是 0.1,相当于1.0×2^-1。
IEEE 754规定:
对于32位的浮点数(float),最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数(double),最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

 32位与64位指的是存储的bit位

3.2.1 浮点数存的过程

IEEE 754 对有效数字M和指数E,还有⼀些特别规定。
前⾯说过, 1 M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表⽰⼩数部分。
IEEE 754 规定,在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去,只保存后⾯的xxxxxx部分。⽐如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。这样做的⽬的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字。
⾄于指数E,情况就⽐较复杂
⾸先,E为⼀个⽆符号整数(unsigned int)
这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存⼊内存时E的真实值必须再加上⼀个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。⽐如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
加上一个中间数,就可以保证得到的为正数存入E中了

3.2.2 浮点数取的过程

指数E从内存中取出还可以再分成三种情况:
E不全为0或不全为1
这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第⼀位的1。
⽐如:0.5 的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位00000000000000000000000,则其⼆进制表⽰形式为:
0 01111110 00000000000000000000000

E全为0  

这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字。
0 00000000 00100000000000000000000

   

E全为1
这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);
0 11111111 00010000000000000000000

与E=0同理,推出无穷大 

3.3 题⽬解析

下⾯,让我们回到⼀开始的练习
先看第1环节,为什么 9 还原成浮点数,就成了 0.000000
9以整型的形式存储在内存中,得到如下⼆进制序列:
0000 0000 0000 0000 0000 0000 0000 1001
⾸先,将 9 的⼆进制序列按照浮点数的形式拆分,得到第⼀位符号位s=0,后⾯8位的指数
E=00000000 ,最后23位的有效数字M=000 0000 0000 0000 0000 1001。
0 00000000 00000000001001
S        E                  M
站在pFloat的视角上看,他会认为自己指向的是一个float类型的值,
由于E全为0,则不再加上省略掉的1.,则为(-1)^0*0000000...1001*2^(0-127)≈0
第二环节

 9.0(10进制)

1001.0(2进制)= (-1)^0 * 1.001 * 2^3

S=0 M=001 E=3+127=130(10进制),10000010(2进制)

pFloat存入内存中则为

0 10000010 001.....(20个0)

以有符号数&d打印出

将0 10000010 001.....(20个0)转化为10进制就为结果

————————————————————————————————

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/516439.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何保持数据一致性

如何保持数据一致性 数据库和缓存&#xff08;比如&#xff1a;redis&#xff09;双写数据一致性问题&#xff0c;是一个跟开发语言无关的公共问题。尤其在高并发的场景下&#xff0c;这个问题变得更加严重。 问题描述&#xff1a; 1.在高并发的场景中&#xff0c;针对同一个…

VC++建立空文档失败的一种情形

假设现在要在单文档程序的客户区创建控件; 把控件作为视类的成员变量; 先把成员变量定义加到视类头文件; 然后在视类的, BOOL CMyttView::PreCreateWindow(CREATESTRUCT& cs) {....... } 在此成员函数中创建控件; 运行程序,就会出现如下错误, 这就需要在类向导…

《捕鱼_ue4-5输出带技能的透明通道素材到AE步骤》

《捕鱼_ue4-5输出带技能的透明通道素材到AE步骤》 2022-05-17 11:06 先看下带透明的特效素材效果1、首先在项目设置里搜索alpha&#xff0c;在后期处理标签设置最后一项allow through tonemapper2、在插件管理器中&#xff0c;搜索movie render &#xff0c;加载movie render q…

《QT实用小工具·十一》Echart图表JS交互之仪表盘

1、概述 源码放在文章末尾 该项目为Echart图表JS交互之炫酷的仪表盘&#xff0c;可以用鼠标实时改变仪表盘的读数。 下面为demo演示&#xff1a; 该项目部分代码如下&#xff1a; #include "widget.h" #include "ui_widget.h" #include "qurl.h&q…

UE小:UE5.3无法创建C++工程

当您在使用Unreal Engine (UE) 构建项目时&#xff0c;如果遇到以下问题&#xff1a; Running C:/Program Files/Epic Games/UE\_5.3/Engine/Build/BatchFiles/Build.bat -projectfiles -project"C:/UEProject/Shp\_1/Shp\_1.uproject" -game -rocket -progress Usi…

Vuex的模块化管理

1&#xff1a;定义一个单独的模块。由于mutation的第二个参数只能提交一个对象&#xff0c;所以这里的ThisLog是个json串。 2&#xff1a;在Vuex中的Store.js中引入该模块 3&#xff1a;在别的组件中通过...mapState调用模块保存的State的值。 4&#xff1a;用...mapMutations修…

界面控件Kendo UI for jQuery 2024 Q1亮点 - 新的ToggleButton组件

Telerik & Kendo UI 2024 Q1 版本于2024年初发布&#xff0c;在此版本中将AI集成到了UI组件中&#xff0c;在整个产品组合中引入AI Prompt组件以及10多个新的UI控件、支持Angular 17、多个数据可视化功能增强等。 P.S&#xff1a;Kendo UI for jQuery提供了在短时间内构建…

递归算法解读

递归&#xff08;Recursion&#xff09;是计算机科学中的一个重要概念&#xff0c;它指的是一个函数&#xff08;或过程&#xff09;在其定义中直接或间接地调用自身。递归函数通过把问题分解为更小的相似子问题来解决原问题&#xff0c;这些更小的子问题也使用相同的解决方案&…

文字超出收起展开功能的实现(vue2)

1.编写展开收起组件 <template><div class"text-clamp"><div class"text" :style"{height}"><span v-if"isVisible" class"btn" click"toggle">{{isExpand ? 收起 : ... 展开}}</spa…

24-Web服务核心功能有哪些,如何实现?

在Go项目开发中&#xff0c;绝大部分情况下&#xff0c;我们是在写能提供某种功能的后端服务&#xff0c;这些功能以RPC API 接口或者RESTful API接口的形式对外提供&#xff0c;能提供这两种API接口的服务也统称为Web服务。 Web服务的核心功能 将这些功能分成了基础功能和高…

day63 单调栈part02

503. 下一个更大元素 II 中等 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更…

基于隐私保护的可追踪可撤销密文策略属性加密方案论文阅读

论文是2022年发表的A Traceable and Revocable Ciphertext-Policy Attribute-based Encryption Scheme Based on Privacy Protection 摘要 本篇论文提出了一种具有用户撤销、白盒追踪、策略策略隐藏功能的CP-ABE方案。在该方案中密文被分为两个部分&#xff1a;第一个部分是和…

Servlet 的基本理解

Servlet 是JavaEE规范的一种&#xff0c;主要是为了扩展Java作为Web服务的功能&#xff0c;统一接口。由其他内部厂商如tomcat&#xff0c;jetty内部实现web的功能。如一个http请求到来&#xff1a;容器将请求封装为servlet中的HttpServletRequest对象&#xff0c;调用init()&a…

【PduR路由】IPduM模块详细介绍

目录 1.IpduM功能简介 2.IpduM模块依赖的其他模块 2.1RTE (BSW Scheduler) 2.2PDU Router 2.3COM 3.IpduM功能详解 3.1 功能概述 3.2 I-PDU多路复用I-PDU Multiplexing 3.2.1 Definitions and Layout 3.2.2通用功能描述 General 3.2.3模块初始化 Initialization 3.…

安装Docker(CentOS)

Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道。 官方网站上…

Kubernetes资源ConfigMap

一、ConfigMap的基本概念 1、什么是configMap ConfigMap资源主要为容器注入相关的程序配置信息,用来定制程序的运行方式,比如Redis监听端口、最大客户端连接数。 当定义好一个ConfiqMap资源后,如果Pod需要使用,可以通过通过环境变量、或存储卷的形式将其挂载并加载相关的…

FLink学习(三)-DataStream

一、DataStream 1&#xff0c;支持序列化的类型有 基本类型&#xff0c;即 String、Long、Integer、Boolean、Array复合类型&#xff1a;Tuples、POJOs 和 Scala case classes Tuples Flink 自带有 Tuple0 到 Tuple25 类型 Tuple2<String, Integer> person Tuple2.…

2024年03月CCF-GESP编程能力等级认证Scratch图形化编程四级真题解析

本文收录于专栏《Scratch等级认证CCF-GESP真题解析》,专栏总目录・点这里 一、单选题(共 10 题,每题 2 分,共 30 分) 第1题 小杨的父母最近刚刚给他买了一块华为手表,他说手表上跑的是鸿蒙,这个鸿蒙是?( )。 A、小程序 B、计时器 C、操作系统 D、神话人物 答案:C…

【React】基于JS 3D引擎库实现关系图(图graph)

主角&#xff1a;3D Force-Directed Graph 简介&#xff1a;一个使用ThreeJS/WebGL进行3D渲染的Graph图库 GitHub: https://github.com/vasturiano/3d-force-graph Ps: 较为复杂或节点巨大时&#xff0c;对GPU>CPU消耗较大&#xff0c;同量级节点对比下优于AntV G6和Echarts…

宁波ISO27001认证:信息安全管理的黄金标准

&#x1f603;宁波ISO27001认证&#xff1a;&#x1f916;信息安全管理的&#x1f4a1;黄金标准 随着信息技术&#x1f4bb;的迅猛发展&#xff0c;信息安全&#x1f50f;问题日益凸显&#xff0c;成为企业&#x1f3ec;稳定运营和持续发展的&#x1f4ca;关键因素。在这样&am…