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

news2025/1/18 9:02:38
⽬录
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进制就为结果

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ansible批量操作(上传文件、删除文件指定文件内容、执行sh文件等)

官方网站 https://www.ansible.com/ 一、Ansible 简介 1、Ansible是新出现的自动化运维工具&#xff0c;完全基于Python开发&#xff0c;集合了众多运维工具&#xff08;puppet、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行…

MinGW使用std::thread报错error: ‘thread‘ is not a member of ‘std‘

目录 问题描述简单的测试代码报错及解决 问题描述 在windows上用vscode编写c代码进行编译时&#xff0c;一直上报error: ‘thread’ is not a member of std’的错误&#xff0c;搜索该错误上报都是说c版本不匹配&#xff0c;然后我在task.json里面添加了-stdc11之后还是报错&…

Spring Boot | Spring Boot的“数据访问“、Spring Boot“整合MyBatis“

目录: 一、Spring Boot”数据访问概述“二、Spring Boot”整合MyBatis”1. 基础环境搭建 (引入对应的“依赖启动器” 配置数据库的“相关参数”)① 数据准备 (导入Sql文件)② 创建项目&#xff0c;引入相应的启动器&#xff0c;编写数据库对应的“实体类”③额外添加pom.xml文…

Nacos下载安装与配置(linux)

一、Nacos下载 官网地址&#xff1a;home (nacos.io) 点击☆&#xff0c;跳转至Github页面。 点击Tags&#xff0c;跳转至版本选择页面&#xff0c;此处选择2.2.0版本。 点击nacos-server-2.2.0.tar.gz&#xff0c;进行下载。 二、将安装包上传至服务器 1.将安装包上传至/usr…

面试官:为什么忘记密码要重置,而不是告诉我原密码?

前端训练营&#xff1a;1v1私教&#xff0c;终身辅导计划&#xff0c;帮你拿到满意的 offer。 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~ Hello&#xff0c;大家好&#xff0c;我是 Sunday。 最近有个同学在面试中遇到了一个很有意思的问题&#xff0c;我相信大多…

SON序列化解决方案

JSON&#xff08;JavaScript Object Notation&#xff09;是一种用于数据交换的轻量级数据格式。在我们日常Python编程中&#xff0c;通常可以使用内置的json模块来进行JSON序列化和反序列化。那么关于使用json模块进行JSON序列化和反序列化的问题解决方案&#xff0c;可以参考…

0基础如何进入IT行业

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 对于没有任何相关背景知识的人来说&#xff0c;如何才能成…

【放假第1天】采购季倒计时 2G 50/年,4G 618/3年 云服务器选购攻略 阿里云 腾讯云 京东云对比 搭建网站、数据分析

更新日期&#xff1a;4月4日&#xff08;阿里云价格回调&#xff0c;京东云采购季持续进行&#xff09; 本文纯原创&#xff0c;侵权必究 【云服务器推荐】价格对比&#xff01;阿里云 京东云 腾讯云 选购指南视频截图 《最新对比表》已更新在文章头部—腾讯云文档&#xff…

腾讯云4核8g服务器性能如何?知道说说

腾讯云4核8G服务器价格&#xff1a;轻量4核8G12M优惠价格646元15个月、CVM S5服务器4核8G配置1437元买1年送3个月。腾讯云4核8G服务器支持多少人同时在线&#xff1f;支持30个并发数&#xff0c;可容纳日均1万IP人数访问。腾讯云百科txybk.com整理4核8G服务器支持多少人同时在线…

SWM341系列应用(上位机应用)

SWM341系列之上位机应用 1、分级图像和PNG、JPG的应用 现象&#xff1a;客户使用SWM34SVET6HMI_0.4.1版本上位机进行UI界面布局&#xff0c;反馈在模拟运行时&#xff08;PC端&#xff09;流畅&#xff0c;在Demo平台&#xff08;设备端&#xff09;运行卡顿。 分析及解决&…

Object类与内部类

废话不多说&#xff0c;直接进入正题。 目录 一、Object类 1.介绍Object类 2.toString方法 3.equals方法 4.hashCode方法 二、内部类 1.静态内部类 2.实例内部类 3.匿名内部类 4.局部内部类 一、Object类 1.介绍Object类 &#xff08;1&#xff09;Object类就是所有…

算法学习——LeetCode力扣补充篇6(132. 分割回文串 II、673. 最长递增子序列的个数、841. 钥匙和房间、463. 岛屿的周长)

算法学习——LeetCode力扣补充篇6 132. 分割回文串 II 132. 分割回文串 II - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。 返回符合要求的 最少分割次数 。 示例 示例 1&#…

一文了解低功耗蓝牙BLE

低功耗蓝牙技术可以构建两种类型的设备:双模设备和单模设备。双模设备既支持经典蓝牙又支持低功耗蓝牙。单模设备只支持低功耗蓝牙。还有仅支持经典蓝牙的设备。 在链路层,设备被分为广播者、扫描者、从设备和主设备。广播者是传输数据包的设备,扫描者是接收广播者的数据包…

ids工业相机与电控位移台同步控制及数据采集

通过VS2017和OpenCV,实现ids工业相机与电控位移台同步控制及数据采集 目录项目环境配置代码流程及思路项目架构项目开发运行效果开发关键ids相机配置位移台环境配置相机头文件相机参数设置保存图像函数设置电控位移台头文件电控位移台设置参数最后就是通过main函数进行调用和控…

美易官方:华尔街分析师最青睐的股票过去五年表现怎么样

华尔街分析师一直被视为金融市场的风向标&#xff0c;他们的推荐和预测往往能影响投资者的决策。然而&#xff0c;分析师的预测并不总是准确无误的&#xff0c;特别是在变幻莫测的股市中。那么&#xff0c;我们不禁要问&#xff0c;华尔街分析师最青睐的股票在过去五年中的表现…

OpenHarmony实战:小型系统移植概述

驱动主要包含两部分&#xff0c;平台驱动和器件驱动。平台驱动主要包括通常在SOC内的GPIO、I2C、SPI等&#xff1b;器件驱动则主要包含通常在SOC外的器件&#xff0c;如 LCD、TP、WLAN等 图1 OpenHarmony 驱动分类 HDF驱动被设计为可以跨OS使用的驱动程序&#xff0c;HDF驱动框…

单总线及DS18B20

目录 单总线 单总线介绍 单总线的电路规范 单总线时序结构 初始化 代码理解 发送一位 代码理解 接收一位 代码理解 发送一个字节 代码理解 接收一个字节 代码理解 DS18B20 DS18B20介绍 引脚及应用电路 内部结构 存储器结构 DS18B20操作流程 ROM指令 功能…

大厂面试之【Redis持久化机制】 - RDB和AOF概述及应用配置

文章目录 Redis持久化1. RDB(Redis DataBase)1.1 概述1.2 配置应用 2. AOF(Append Only File)2.1 概述2.2 配置应用 Redis持久化 先上结论&#xff1a;Redis持久化操作分为rdb以及aof&#xff0c;但是前者已经够用 1. RDB(Redis DataBase) 1.1 概述 rdb保存的是dump.rdb文件在指…

基于springboot实现校园资料分享平台系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校园资料分享平台演示 摘要 随着信息互联网购物的飞速发展&#xff0c;国内放开了自媒体的政策&#xff0c;一般企业都开始开发属于自己内容分发平台的网站。本文介绍了校园资料分享平台的开发全过程。通过分析企业对于校园资料分享平台的需求&#xff0c;创…

C++ 11是如何封装Thread库的?

引言 C11 标准引入了一个重要的特性&#xff0c;即原生线程支持&#xff0c;这标志着C语言在并发编程领域迈出了坚实的步伐。在此之前&#xff0c;开发人员在进行跨平台的多线程编程时&#xff0c;不得不依赖于操作系统提供的特定API&#xff0c;如Windows API或POSIX Threads…