当前位置: 首页 > news >正文

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

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

  • 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;
}

相关文章:

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

第十六讲&#xff1a;数据在内存中的存储 1.整数在内存中的存储1.1存储方式1.2大小端字节序1.3大小端字节序排序规则1.4为什么要有大小端1.5练习1.5.1练习11.5.2练习21.5.3练习31.5.4练习41.5.5练习51.5.6练习61.5.7练习7 2.浮点数在内存中的存储2.1练习2.2浮点数的存储2.3浮点…...

【EXCEL_VBA_基础知识】15 使用ADO操作外部数据

课程来源&#xff1a;王佩丰老师的《王佩丰学VBA视频教程》&#xff0c;如有侵权&#xff0c;请联系删除&#xff01; 目录 1. 使用ADO链接外部数据源 2. 常用SQL语句&#xff08;Execute(SQL语句)&#xff09; 2.1 查询数据、查询某几个字段、带条件查询、合并两表数据、插…...

如何在Spring中配置Bean?

在Spring框架中配置Bean&#xff0c;主要有以下几种方式&#xff1a; XML配置文件注解配置Java配置类 1. XML配置文件 早期的Spring版本广泛使用XML配置文件来定义和配置Bean。在XML中&#xff0c;可以通过 <bean> 标签定义Bean&#xff0c;指定其类、唯一标识符&…...

深入学习 torch.distributions

0. 引言 前几天分几篇博文精细地讲述了《von Mises-Fisher 分布》, 以及相应的 PyTorch 实现《von Mises-Fisher Distribution (代码解析)》, 其中以 Uniform 分布为例简要介绍了 torch.distributions 包的用法. 本以为已经可以了, 但这两天看到论文 The Power Spherical dist…...

Java中的判断校验非空问题

目录 字符串 字符串是空的情况 字符串不是空的情况 对象 对象是空的情况 对象不是空的情况 前端传的 int ,double类型等等 Optional 判断情况 https://www.cnblogs.com/zhangboyu/p/7580262.htmlhttps://www.cnblogs.com/zhangboyu/p/7580262.html 值为空的情况,不会…...

webman使用summernote富文本编辑器

前言 Summernote富文本编辑器功能强大&#xff0c;可以直接从word直接复制内容过来而不破坏原有的文档格式&#xff0c;非常适合做商品详情等内容的编辑工具。本文将展示如何在php高性能框架webman中使用summernote编辑器。 下载 去Bootstrap 中文网、Summernote、jQuery官网…...

jQuery里添加事件 (代码)

直接上代码 <!DOCTYPE html> <html><head></head><body><input type"text" placeholder"城市" id"city" /><input type"button" value"添加" id"btnAdd" /><ul id…...

Java数组的使用

Java数组的使用 前言一、数组基本用法什么是数组注意事项创建数组基本语法代码示例注意事项 数组的使用代码示例获取长度 & 访问元素注意事项 下标越界遍历数组使用 for-each 遍历数组 二、数组作为方法的参数基本用法代码示例打印数组内容 理解引用类型代码示例参数传内置…...

如何参与github开源项目并提交PR

&#x1f47d;System.out.println(“&#x1f44b;&#x1f3fc;嗨&#xff0c;大家好&#xff0c;我是代码不会敲的小符&#xff0c;目前工作于上海某电商服务公司…”); &#x1f4da;System.out.println(“&#x1f388;如果文章中有错误的地方&#xff0c;恳请大家指正&…...

拼多多携手中国农业大学,投建陕西佛坪山茱萸科技小院

5月16日下午&#xff0c;中国农业大学陕西佛坪山茱萸科技小院在佛坪县银厂沟村揭牌。佛坪县素有“中国山茱萸之乡”的美誉&#xff0c;是全国山茱萸三大基地之一&#xff0c;当地山茱萸是国家地理标志产品&#xff0c;山茱萸肉产量位居全国第二。 为充分发挥佛坪县得天独厚的山…...

技术前沿 |【自回归视觉模型ImageGPT】

自回归视觉模型ImageGPT 引言一、ImageGPT的基本原理与创新之处二、ImageGPT在图像生成、理解等视觉任务上的应用三、ImageGPT对后续视觉Transformer模型发展的影响四、ImageGPT的深入应用 引言 在人工智能的飞速发展中&#xff0c;视觉模型作为其中一个重要的分支&#xff0c…...

Manjaro linux install RedisGUI (RedisInsight)亲测2024-5-25

Arch 用户仓库(Arch User Repository)(AUR) 是用户选择 基于 Arch Linux 的系统 的一个主要理由。你可以在 AUR 中访问到大量的附加软件。 (LCTT 译注&#xff1a;AUR 中的 PKGBUILD 均为用户上传且未经审核&#xff0c;使用者需要自负责任&#xff0c;在构建软件包前请注意检…...

debian/control文件中常见字段的介绍

1 简介 在Debian或基于Debian的发行版中&#xff0c;debian/control文件是软件包管理的关键部分。它包含了软件包的各种元数据和安装脚本信息&#xff0c;用于软件包管理系统&#xff08;如dpkg&#xff09;识别如何处理该软件包。以下是debian/control文件中常见字段的详细介…...

c++题目_农场和奶牛

&#x1d435;B 头奶牛 (1≤&#x1d435;≤25000)(1≤B≤25000)&#xff0c;有 &#x1d441;(2&#x1d435;≤&#x1d441;≤50000)N(2B≤N≤50000) 个农场&#xff0c;编号 11 到 &#x1d441;N&#xff0c;有 &#x1d440;(&#x1d441;−1≤&#x1d440;≤100000)M(…...

DDD领域设计在“图生代码”中的应用实践

前言 领域驱动设计(简称 ddd)概念来源于2004年著名建模专家Eric Evans 发表的他最具影响力的书籍:《领域驱动设计——软件核心复杂性应对之道》&#xff08;Domain-Driven Design –Tackling Complexity in the Heart of Software&#xff09;&#xff0c;简称Evans DDD。领域…...

LabVIEW舱段测控系统开发

LabVIEW舱段测控系统开发 在航空技术飞速发展的当下&#xff0c;对于航空器的测控系统的需求日益增加&#xff0c;特别是对舱段测控系统的设计与实现。开发了一款基于LabVIEW开发的舱段测控系统&#xff0c;包括系统设计需求、系统组成、工作原理以及系统实现等方面。 开发了…...

[leetcode]第 n个丑数

我们把只包含质因子 2、3 和 5 的数称作丑数&#xff08;Ugly Number&#xff09;。求按从小到大的顺序的第 n 个丑数。 示例: 输入: n 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。 1 2 3 说明: 1 是丑数。 n 不超过1690。 class Solution {public…...

STM32-电灯,仿真

目录 1.配置vscode 2.新创建软件工程 3.仿真 4.源码 5.运行效果 1.配置vscode http://t.csdnimg.cn/BvCLx 安装 C/C Extension Pack 安装 Embedded IDE 安装 Keil MDK 配置路径 2.新创建软件工程 下拉找到对应的 输入项目名字,选择项目所在文件夹即可 3.仿真 一路新…...

《SpringBoot》系列文章目录

SpringBoot是由Pivotal团队提供的全新框架&#xff0c;旨在简化新Spring应用的初始搭建以及开发过程。以下是一些关于SpringBoot的详细介绍&#xff1a; 设计目的&#xff1a;SpringBoot通过特定的方式来进行配置&#xff0c;使得开发人员不再需要定义样板化的配置&#xff0c…...

牛客小白月赛94VP

1.签到&#xff1a;https://ac.nowcoder.com/acm/contest/82957/A 下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace std; map<int,int> mp; int main() {for(int i1;i<9;i){int x;cin>>x;mp[i]x;}string s;cin>>s;s s;for(int i…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...