第十六讲:数据在内存中的存储

第十六讲:数据在内存中的存储

  • 1.整数在内存中的存储
    • 1.1存储方式
    • 1.2大小端字节序
    • 1.3大小端字节序排序规则
    • 1.4为什么要有大小端
    • 1.5练习
      • 1.5.1练习1
      • 1.5.2练习2
      • 1.5.3练习3
      • 1.5.4练习4
      • 1.5.5练习5
      • 1.5.6练习6
      • 1.5.7练习7
  • 2.浮点数在内存中的存储
    • 2.1练习
    • 2.2浮点数的存储
    • 2.3浮点数的存储过程
      • 2.3.1符号位的存储
      • 2.3.2对于有效数字M的存储
      • 2.3.3对于指数E的存储
        • 2.3.3.1E不全为0或不全为1
        • 2.3.3.2E全为0
        • 2.3.3.3E全为1
    • 2.4题目解析

这一讲分别介绍了整数和浮点数在内存中的存储方式,以及一些题目的解析

1.整数在内存中的存储

1.1存储方式

数据在内存中的存储都是以其二进制位来表示的,而整数的二进制位的表示方法有三种:原码、反码、补码,在内存中,存储的是正数的补码
正数的原码、反码、补码相同
负数的三种表示方式各不相同

那么为什么整数存储的是补码呢?

1.CPU只有加法器,使用补码能够将字符位和数值位统一处理
2.原码和补码进行转换的过程是相同的,不需要额外的硬件电路便可以实现

1.2大小端字节序

当我们对于一个整数变量进行内存监视时,常常会观察到整数的存放顺序和我们创建的变量值顺序是不同的,例如:
在这里插入图片描述
当我们创建了一个a变量时,它在内存中的存储为(VS编译器):
在这里插入图片描述
可以看见,它是倒着存的,不是正着存的,这就涉及到了整数存储顺序的两种方式:大端存储和小端存储

1.3大小端字节序排序规则

大端排序方式:

低位的字节放在高地址,高位的字节放在低地址

小端排序方式:

低位的字节放在低地址,高位的字节放在高地址

我们画图来解析:
在这里插入图片描述

1.4为什么要有大小端

我们常⽤的 X86 结构是⼩端模式,⽽KEIL C51 则为⼤端模式。很多的ARM,DSP都为⼩端模式。有些ARM处理器还可以由硬件来选择是⼤端模式还是⼩端模式。

但是为什么要有着大小端的存在呢?

1.C语言有着多种类型的数(float、 int、char),对于字节安排的问题,必然要被得到处理
2.不同的硬件设计可能导致不同的存储方式,硬件的设计使用某种存储方式可能会优化性能或简化设计
3.不同的存储方式可能对性能有不同的影响

1.5练习

总结:
1.整数在运算时(整型提升、加法、减法)都是补码在进行运算
2.对于整数的打印,分为两种情况:

1.打印有符号整数,如果需要整形提升,那么补的是符号位,将补码转换成原码,进行计算之后将得出值进行打印
2.打印无符号整数,如果需要整形提升,如果最高位为1,补1,为0,补0,和有符号整数相同,但是计算结果时看的是补码,因为无符号整数的原码、反码、补码相同

1.5.1练习1

//设计⼀个⼩程序来判断当前机器的字节序。
//
//设计思路:
//创建一个a变量,赋值为1,其在内存中的存储应该为00 00 00 01
//①如果为小端存储:存储方式应该为01 00 00 00
//②如果为大端存储:存储方式为00 00 00 01
//分别拿出它们首个字节,如果值为1,就是小端存储,如果值位0,就为大端存储
//
//代码1:
int main2()
{int a = 1;if (*((char*)&a))  //注意:这里为&a,因为只能将地址强转成(char*)类型的指针,否则可能会出现越界访问printf("小端存储\n");elseprintf("大端存储\n");return 0;
}//代码2:
int DefA()
{int a = 1;return *((char*)&a);
}int main()
{int ret = DefA();if (ret)printf("小端存储\n");elseprintf("大端存储\n");return 0;
}

1.5.2练习2

//1.5.2练习2
int main()
{char a = -1;//对于char类型的变量,它可能时signed char类型,也可能是unsigned char类型,具体取决于编译器,这里是有符号类型//char类型为一个字节,此时,-1的2进制表示为10000001,它的补码为:11111111//因为-1为整形,所以它的补码结果为:11111111111111111111111111111111,而a为char类型,char类型只能存储11111111,所以对于a://补码:11111111,由于要进行打印,发生整形提升,结果为11111111111111111111111111111111//原码:10000000000000000000000000000001//所以结果为-1signed char b = -1;//char类型在此编译器下就是有符号类型的,所以对于有符号类型的char分析和上面一样//所以结果为-1unsigned char c = -1;//对于无符号类型,仍为1个字节,所以a还是11111111//整型提升结果为00000000000000000000000011111111,因为对于无符号整形,整形提升加0//此时符号位为0,所以原码和补码相同,计算的结果为255printf("a=%d,b=%d,c=%d", a, b, c);//以%d形式打印,表示打印有符号整数return 0;
}

1.5.3练习3

//1.5.3练习3
int main()
{char a = -128;//-128,原码为10000000000000000000000001000000,反码为11111111111111111111111110111111,补码为11111111111111111111111111000000//所以a里存的是11000000//要打印的是无符号整形,进行整形提升,结果为11111111111111111111111111000000//所以结果为4294967168printf("%u\n", a);return 0;
}

1.5.4练习4

//1.5.4练习4
int main()
{char a = 128;//对于128,它的原码为00000000000000000000000010000000//反码:01111111111111111111111101111111//补码:01111111111111111111111110000000//存储到a里,结果为10000000//打印无符号整形,整形提升//补码:11111111111111111111111110000000printf("%u\n", a);return 0;
}

但是,看练习4,当我们要将128这个值存到char类型中时,a为10000000,这显然就是-128呀!这是因为char类型的取值范围为-128 - 127,128根本存不下,这时存储遵循一个规律:
在这里插入图片描述
所以我们可以将他们看成一个循环,对于其他类型的整数(float、int)也是如此

1.5.5练习5

//1.5.5练习5
#include <string.h>int main()
{char a[1000];int i;for (i = 0; i < 1000; i++){a[i] = -1 - i;//strlen是求字符串长度的函数,遇到\0会停止//对于一个char类型的数组,里面放的元素为char类型//而我们已经了解到了,char类型的取值范围为-128 - 127//所以a数组中放的值只能为:-1 -2 -3 ... -127 -128 127 126 ... 2 1 0这些ASCII码值对应的字符//遇到\0停止,所以结果为255}printf("%zd", strlen(a));return 0;
}

1.5.6练习6

//1.5.6练习6
unsigned char i = 0;int main()
{for (i = 0; i <= 255; i++){//无符号char类型的取值范围为0-255,所以会一直满足循环条件,会一直循环进行打印printf("hello world\n");}return 0;
}
#include <windows.h>int main()
{unsigned int i;for (i = 9; i >= 0; i--){//对于无符号int类型,他所有的位都会被当成数值位,所以它不会出现负数的情况//所以它会一直满足条件,一直进行打印printf("%u\n", i);Sleep(100);}return 0;
}

1.5.7练习7

//1.5.7练习7
//X86环境 ⼩端字节序
int main()
{int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1);//&a取出的是整个数组的地址,+1表示紧挨着数组的那块地址,将其强转成int*类型的指针赋给ptr1//*(ptr-1)得到的就是4int* ptr2 = (int*)((int)a + 1);//a表示首元素的地址,将其转换成int类型,表示的是一个数!,+1表示地址加1,直接+1就可以了//但是要注意:每一个字节都有一个指针,+1表示的是向后偏移一个字节//对于a,在内存中的存储为0x 01 00 00 00 02 00 00 00 ...(因为为小端存储),向后偏移一个字节,就变成了://00 00 00 02 00 00 00//对他解引用,访问4个字节,所以找到了00 00 00 02,因为为小端存储,所以结果为02000000printf("%x,%x", ptr1[-1], *ptr2);return 0;
}

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

2.1练习

浮点数的存储和整形的存储是不一样的,下面我们就通过一个练习来直观地感受一下:

//2.1练习
int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n", n);//9printf("*pFloat的值为:%f\n", *pFloat);//0.000000*pFloat = 9.0;printf("num的值为:%d\n", n);//1091567616printf("*pFloat的值为:%f\n", *pFloat);//9.000000return 0;
}

2.2浮点数的存储

既然知道了整形和浮点型的不同,那么浮点数是怎么存储的呢?

根据国际标准IEEE(电气和电子工程协会) 754,任意⼀个⼆进制浮点数V可以表示成下⾯的形式:
在这里插入图片描述
我们通过举例来说:

//2.2浮点数的存储
int main11()
{float a = 5.5;//我们来探讨5.5在内存中的存储形式://5的二进制表示为101.1,写成科学计数法的形式为1.011 * 10^2//所以符号位S为0(因为为整数)//指数位E = 2//数值位为M = 1.011return 0;
}

如果没有看懂,我们通过图像来直观感受:
在这里插入图片描述

我们可以简单理解S、E、M这三个值如上

IEEE 745规定:
1.对于32位的浮点数,最高的一位存储的是符号位,接着八位存储指数E,剩下32位存储有效数字M
2.对于64位的浮点数,最高的一位存储的是符号位,接着十一位存储指数E,剩下52位存储有效数字M

在这里插入图片描述

2.3浮点数的存储过程

2.3.1符号位的存储

符号位的存储只占据一个字节,很简单,是正数就是0,是负数就是1

2.3.2对于有效数字M的存储

其实M的取值范围为1<=M<2,也就是说,M总是可以表示成1…的形式,所以IEEE 754规定,在计算机保存M时,只保存小数点后边的部分,前边的1舍去,等到读取的时候,再将1加上去,这样就节省了一位有效数字,使得精度更高,比如:1.01在进行存储时,只存储01,读取时再将1加上;0.10可以表示成1.0 * 10的负一次幂,所以说它在存储时存储0就可以了,需要注意的是:它要在后边补0,也就是说对于1.1,在存储时存储的是01000000000000000000000

2.3.3对于指数E的存储

对于指数的存储比较复杂,分为三种情况讨论:

2.3.3.1E不全为0或不全为1

因为E的值可能为负数,为了将负数表示出来,我们需要将E的值加上127(在32位机器上,偏移值为127,在64位机器上,偏移值为1023),再将其转换成二进制存储即可,这样即可以通过比较指数的大小来判断两个浮点数的大小关系,同时也可以方便地进行加减乘除等计算操作

这种情况为正常情况,比如0.5的二进制表示形式为0.1,也就是1.0 * 10的负一次幂,在存储数值位时要将数值位的一忽略,所以存储时存储的就是0,补齐23位,也就是00000000000000000000000,指数位值为-1,加上127为126,二进制表示为01111110,符号位为0,所以0.5的二进制表示为:

0 01111110 00000000000000000000000
2.3.3.2E全为0

当E全为0时,指数位的值为1-127(它是规定好的),而且此时数值位在进行复原时,补的不是1了,而是0,此时表示的是一个无限接近于0的一个小数

2.3.3.3E全为1

这时表示的是一个无穷大的数

2.4题目解析

//2.4题目解析
int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n", n);//n本来就是一个int类型的数,进行打印,结果为9printf("*pFloat的值为:%f\n", *pFloat);//对于9://原码:00000000000000000000000000001001//对于一个float类型的数,因为要解引用,拿到的是原码://符号位:0 - 正数//数值位:00000000000000000001001 - 0.00000000000000000001001//指数位:00000000 - 原码为00000000 - 1-127 = -126//所以值为0.00000000000000000001001 * 10的-126次幂//他表示0.0000000000000000000...1001是一个很小的数//尽管要拿出来,拿出的也只是0.000000,所以结果为0.000000*pFloat = 9.0;//9的二进制表示1001.0 - 1.001 * 10 ^ 3//符号位:0 - 正数//数值位:1.001 - 00100000000000000000000 - 注意:要在后边补0//指数位:3 + 127 = 130 - 10000010//全部 —— 0 10000010 00100000000000000000000 - 1,091,567,616printf("num的值为:%d\n", n);全部 —— 0 10000010 00100000000000000000000 - 1,091,567,616printf("*pFloat的值为:%f\n", *pFloat);//直接打印出9.000000即可return 0;
}

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

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

相关文章

如何将数据从一部手机传输到另一部手机[安全快速]

概括 手机之间无需使用蓝牙即可传输文件&#xff0c;配合专业的文件传输工具更高效。本文将向您介绍几种使用不同的数据传输工具快速安全地将数据从一部手机传输到另一部手机的方法&#xff0c;特别是当有大文件或大量文件时。现在&#xff0c;我们来看看。 需要在朋友或家人之…

Rust 赋能前端 -- 写一个 File 转 Img 的功能

所有耀眼的成绩,都需要苦熬,熬得过,出众;熬不过,出局 大家好,我是柒八九。一个专注于前端开发技术/Rust及AI应用知识分享的Coder 此篇文章所涉及到的技术有 Rustwasm-bindgen/js-sys/web-sysWeb WorkerWebAssemblyWebpack/Vite配置WebAssemblyOffscreenCanvas脚手架生成项…

校园二手书交易|基于SprinBoot+vue的校园二手书交易管理系统(源码+数据库+文档)

校园二手书交易管理系统 目录 基于SprinBootvue的校园二手书交易管理系统 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3 卖家用户功能模块 4 用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八…

基于springboot+html的二手交易平台(附源码)

基于springboothtml的二手交易平台 介绍部分界面截图如下联系我 介绍 本系统是基于springboothtml的二手交易平台&#xff0c;数据库为mysql&#xff0c;可用于毕设或学习&#xff0c;附数据库 部分界面截图如下 联系我 VX&#xff1a;Zzllh_

在家庭影院音频中应用的D类音频放大器

家庭影院的主要组成部分包括显示设备、音响设备、信号源和接线设备等。家庭影院的音响信号需要进行处理和输出&#xff0c;以获得高质量的音效。音响设备通常需要一台功率适当的数字、模拟混合的处理器&#xff0c;对音源进行降噪、均衡、扩展等处理操作&#xff0c;以达到高品…

【智能算法应用】北方苍鹰算法求解二维栅格路径规划问题

目录 1.算法原理2.二维路径规划数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】北方苍鹰优化算法&#xff08;NGO)原理及实现 2.二维路径规划数学模型 栅格法模型最早由 W.E. Howden 于 1968 年提出&#xff0c;障碍物的栅格用黑色表示&#xff0c;可通过的…

ping 探测网段哪些地址被用

#!/bin/bash# 遍历192.168.3.1到192.168.3.254 for i in {1..254} doip"192.168.3.$i"# 对每个IP地址进行三次ping操作if ping -c 3 -W 1 $ip > /dev/null 2>&1thenecho "$ip: yes"fi done$ sh test.sh 192.168.3.1: yes 192.168.3.95: yes 192.…

使用Word表格数据快速创建图表

实例需求&#xff1a;Word的表格如下所示&#xff0c;标题行有合并单元格。 现在需要根据上述表格数据&#xff0c;在Word中创建如下柱图。如果数据在Excel之中&#xff0c;那么创建这个图并不复杂&#xff0c;但是Word中就没用那么简单了&#xff0c;虽然Word中可以插入图表&a…

014_C标准库函数之<stdio.h>

【背景】 今天这个主要说的是<stdio.h>头文件&#xff0c;大家众所周知&#xff0c;这个是我们学习C语言时第一个接触到的头文件了&#xff0c;那么为什么我不一开始就介绍这个头文件呢&#xff1f;我觉得有两个原因&#xff0c;如下&#xff1a; 1.一开始大家的编程思…

LeetCode/NowCoder-链表经典算法OJ练习3

孜孜不倦&#xff1a;孜孜&#xff1a;勤勉&#xff0c;不懈怠。指工作或学习勤奋不知疲倦。&#x1f493;&#x1f493;&#x1f493; 目录 说在前面 题目一&#xff1a;返回倒数第k个节点 题目二&#xff1a;链表的回文结构 题目三&#xff1a;相交链表 SUMUP结尾 说在前…

MySQL库/表/数据的操作

文章目录 1.数据库操作1.1 创建、删除、查看和修改1.2 编码格式1.3 备份和恢复 2.表的操作2.1 创建表2.2 存储引擎2.3 查看表、修改表、删除表 3.数据类型3.1整数类型3.2字节类型(bit)3.3浮点类型(bit)3.4 decimal3.5 字符串类型3.6 日期和时间类型3.7 enum和set关于如何查找想…

Python中别再用 ‘+‘ 拼接字符串了!

大家好&#xff0c;在 Python 编程中&#xff0c;我们常常需要对字符串进行拼接。你可能会自然地想到用 操作符将字符串连接起来&#xff0c;毕竟这看起来简单明了。 在 Python 中&#xff0c;字符串是不可变的数据类型&#xff0c;这意味着一旦字符串被创建&#xff0c;它就…

【Python】—— lambda表达式

目录 &#xff08;一&#xff09;应用场景 &#xff08;二&#xff09;lambda 语法 &#xff08;三&#xff09;示例分析 &#xff08;四&#xff09;lambda参数形式 4.1 无参数 4.2 一个参数 4.3 默认参数 4.4 可变参数 &#xff1a;*args 4.5 可变参数 &#xff1a;…

基于Matlab实现BP神经网络的手写数字识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 手写数字识别是计算机视觉和模式识别领域的一个经典问题&#xff0c;具有广泛的应用场景&…

信息安全从业者书单推荐

作为一名网安人&#xff0c;身上肩负的责任是很大的&#xff0c;能力越大&#xff0c;责任也越大&#xff0c;反过来责任越大&#xff0c;能力也必须跟得上。不管是想进这行&#xff0c;还是已经在这行&#xff0c;持续学习肯定是不能缺少的&#xff0c;除了在工作中积累&#…

从0开始写一个环境保护网站的第3天(JAVAWEB)

1.目标 实现首页的环境保护原因的查询&#xff0c;和底部友情连接部分 2.实现 2.1建立数据库表格&#xff08;这里数据全是百度查询&#xff09; 环境保护原因表&#xff1a; 友情连接表&#xff1a;&#xff08;数据来源https://zhuanlan.zhihu.com/p/696243646&#xff0…

SqlSession是什么?在MyBatis-Spring中有什么应用?

目录 一、SqlSession是什么 二、SqlSession在MyBatis中的应用 三、SqlSession在Spring中的应用 一、SqlSession是什么 SqlSession 是 MyBatis 框架中的一个核心概念&#xff0c;它代表与数据库的一次会话。MyBatis 是一个流行的 Java 持久层框架&#xff0c;用于简化数据库…

【Linux】fork和exec中的信号继承探索

fork和exec中的信号继承探索 一、结论二、代码验证2.1 代码编写2.2 代码执行 三、linux源码验证四、APUE中的验证五、其他 一、结论 fork时子进程会继承父进程的信号处理方式&#xff0c;包括父进程设置信号为SIG_DFL或SIG_IGN或捕获后设置自定义处理函数。exce时子进程会继承…

ChatGPT写作指南:掌握5种高效格式成为写作达人【含实用示例】

1. **简洁指令** 当任务较简单时&#xff0c;可以用一小段话来说明&#xff0c;便于理解和执行。如下例&#xff1a; 背景&#xff1a;我负责运营一个旅游主题的社交媒体账号。 角色&#xff1a;作为一位经验丰富的文案创作专家&#xff0c;我擅长打造引人注目的旅游内容…

【无标题】亚马逊5月24日宣布推出2024出口跨境物流加速器计划

亚马逊中国5月24日郑重宣布启动“2024亚马逊出口跨境物流加速器计划”&#xff0c;旨在依托其世界领先的物流网络和前沿技术&#xff0c;结合本土资源&#xff0c;不断优化跨境物流服务&#xff0c;以强化中国卖家在跨境物流供应链管理方面的能力&#xff0c;进而提升整体效率&…