首页 > 系统相关 >数据在内存中的存储

数据在内存中的存储

时间:2024-03-20 11:32:01浏览次数:20  
标签:存储 00000000 浮点数 补码 char 内存 数据

文章目录

数据在内存中的存储

整数在内存中的存储

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

整数的二进制表示有三种:原码、反码、补码

对于有符号整数,它的最高位视为符号位,1表示负,0表示正。

正整数的原码、反码、补码相同。

负整数的原码、反码、补码不同:

原码:将原数直接写成二进制表示的形式

反码:符号位不变,其余各位取反

补码:反码加一

补码转化为原码:1.补码建1,再取反(符号位不变)2.补码取反(符号位不变),再加1,与原码转化为补码的过程一致。

为什么计算机存储的是补码呢?

在计算机系统中,数值⼀律⽤补码来表⽰和存储。

原因在于,使⽤补码,可以将符号位和数值域统⼀处理; 同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。


大小端字节序存储

大小端

超过一个字节的数据在内存中存储时会出现存储顺序的问题,基于此,我们按照不同的存储顺序分为大端字节序存储和小端字节序存储。

大端字节序存储

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

小端字节序存储

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

  • 以VS为例:

首先,VS调试的内存窗口是以十六进制表示的,这么做只是为了方便展示,并不能说明内存中是如此存储的。

129的二进制表示为:00000000 00000000 00000000 10000001

将上面的二进制序列化为十六进制表示:00 00 00 81

对于这个十六进制序列,81相对00就是低位,我们联想一下十进制的54,4是个位,就是低位。

在这里插入图片描述

在这里插入图片描述

而我们观察第二张图,低位的81存储在了较低地址处,按照上面介绍的大小端字节序存储,我们可以得出结论VS采用小端字节序存储。


了解到这里,我们尝试应对百度的一道题目:

写一个程序,判断当前机器是大端还是小端:

//1.指针
int check_sys()
{
    int i = 1;
    return *((char*)&i);
}

int main()
{
    int ret = check_sys();
    if (1 == ret)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}
//思路就是,我们创建一个整型类型,赋值为1,1的二进制表示为00000000 00000000 00000000 00000001
//取变量的地址,将它强制类型转换为char*类型,然后解引用,char*类型解引用访问一个字节。
//如果结果是0,证明当前机器存储1的顺序是00000000 00000000 00000000 00000001,为大端字节序存储。
//如果结果是1,证明当前机器存储1的顺序是00000001 00000000 00000000 00000000,为小端字节序存储。
//联合
int chack_sys()
{
    union
    {
        int i;
        char c;
    }un;
    un.i = 1;
    return un.c;
}

int main()
{
    int ret = check_sys();
    if (1 == ret)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

在这里插入图片描述

我们对i赋值1,会改变c的值

如果是小端字节序存储:c的位置存储的是00000001

如果是大端字节序存储:c的位置存储的是00000000

如此我们便判断出当前机器的大小端。


我们知道,char类型其实也是整型家族的一员,char也有无符号char和有符号char,char究竟默认为有符号char还是无符号char,这是不确定的,取决于编译器。不过,VS的char默认就是有符号char

这段代码的输出结果是什么?

#include <stdio.h>

int main()
{
    char a = -1;//标号1
    signed char = -1;//标号2
    unsigned char = -1;//标号3
    printf("a=%d,b=%d,c=%d",a,b,c);
    return 0;
}

VS2022环境下,输出的结果是

在这里插入图片描述

为什么会出现这种情况?

观察题目,标号1和标号2的语句其实是一样的,因为VS2022下的char默认为有符号char。

首先写出-1在内存中存储的补码:11111111 11111111 11111111 11111111

a变量无法存储32个bit位,发生截断,截取最低位起8个bit位:11111111,这就是a变量在内存中存储的二进制序列

我们以%d(有符号整数)的形式打印,首先会整型提升,整型提升有两种情况,char是有符号的,所以整型提升时补符号位,这里是1,得到:11111111 11111111 11111111 11111111

以有符号整型打印,计算机认为整型提升后的二进制序列是一个有符号整数的补码,最高位是1,为负数,原码、反码、补码不同,打印时需要转化为原码:10000000 00000000 00000000 00000001,转化过来,就是-1,所以打印a、b的结果都是-1。

对于c我们采取同样的步骤分析:

-1的补码为:11111111 11111111 11111111 11111111,存储在unsigned char中会发生截断,存储的是:11111111

以%d形式打印,发生整型提升,此时c是无符号char类型,整型提升时补0,得到:00000000 00000000 00000000 11111111

最高位为0,是正数,原码、反码、补码相同,所以整型提升后的二进制序列就是原码,就是255,所以打印255。


我们再看一道题目:

#include <stdio.h>

unsigned char i = 0;
int main()
{
    for(i = 0; i <= 255; i++)
    {
        printf("hello world\n");
    }
    return 0;
}

打印结果是什么?

答案是:死循环,一直打印hello world。

unsigned char类型的取值范围是0~255

当i = 255时,其在内存中的存储是11111111

当第256次循环时,i 理应是256,但是不是这样的:

256的二进制表示为:00000000 00000000 00000001 00000000

存储在i中,会发生截断只取8个bit位00000000,i的值其实是0,然后再次到255,如此构成死循环,也就是说i <= 255这个条件恒成立。

浮点数在内存中的存储

浮点数在内存中的存储不同于整数在内存中的存储。

根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

V = (-1)^S * M * 2^E

  • **(-1)^S: ** 为符号位,S为0表示正数;S为1表示负数。
  • **M: ** 表示有效数字,它的大小大于1,小于2.
  • 2^E: 表示指数位

对于上述知识,我们举个例子来解释:

十进制表示的浮点数5.5
二进制表示:101.1 (小数点后面的第一位权重为2^-1)
我们将它写成由S、M、E表示的形式:(-1)^0 * 1.011 * 2^2
S;0
M:1.011
E:2

我们发现,如果我们知道任意一个浮点数的上述表示形式的S、M、E,我们就能将这个浮点数还原成我们常见的十进制表示形式。

其实,浮点数在内存中存储的就是S、M、E的值。


对于32位的浮点数(float),它的最高位存储S,8个bit位存储E,23个bit位存储M

在这里插入图片描述
对于64位的浮点数(double),它的最高位存储S,11个bit位存储E,52个bit位存储M
在这里插入图片描述

首先,最高位存的S很简单,是负数就存1,是正数就存0。

我们前面举了十进制5.5的例子,M为1.011,存储M时其实并不会存小数点前的1,23个位存储的是小数点后面的数011,这样做的好处是:能够多存储一位,增加了浮点数存储的精确度。

标准规定E是一个无符号整数

我们清楚,科学计数法的指数可能为负数。针对这种情况,引入了一个中间值(32位浮点数为127,64位浮点数为1023),规定在存储E时,要先加上这个中间值,比如某个32位浮点数的E为3,那么真实存储的为127 + 3 = 130,如果E为-1,那么真实存储的是-1 + 127 = 126。标准规定的这个中间值是很巧妙的,保证不会出现某个指数E加上中间值为负数的情况,这一点我们不必担心。

S的取很简单,我们不多赘述。

我们在取的时候大致分为三种情况:

  • E不全为0且E不全为1

    将存储的E拿出来后,减去中间值,得到E的值,然后拿出M的值,并在前面加上1.

  • E全为0

    我们想,我们存储E时要加上一个中间值,而加上了这个中间值,E在计算机种存储的仍然全为0,所以我们知道,这会是一个非常小的数。对于这个非常小的数,取的时候E默认为1 - 127,同时取出M时,不再会加上1,而是以0点几的形式拿出来。

  • E全为1

    这种情况一定是一个很巨大的数,这个数取出来后是无穷大,符号由S决定。

我们举个例子:

例如我们存十进制的5.5
二进制表示:101.1
转化为S、M、E的形式:(-1)^S * 1.011 * 2^2
我们假设这个数是float类型的
那么它存储在计算机的二进制序列为:
0 10000010 01100000000000000000000

在这里插入图片描述

解析

存:

正数,所以S是0

E是2,32位浮点数存储E时会加上中间值127,所以存储在计算机内部的其实是127 + 2 = 129这个数字

M存储时,不存小数点前面的1,只存储小数点后面的011,不够的补0,所以M存储为01100000000000000000000

取:

S取出来是0,所以是正数

E取出来是129,减去中间值127 ,得到2

由于E的存储不全为0且不全为1,所以M取出来后加上1,得到1.011

再根据取出来的S、M、E就能还原出十进制32位浮点数5.5。

标签:存储,00000000,浮点数,补码,char,内存,数据
From: https://blog.csdn.net/xiaokuer_/article/details/136864406

相关文章

  • 数据结构(C语言版)——单链表的查找
    1.按位查找//按位查找,返回第i个元素(带头结点)LNode*GetElem(LinkListL,inti){ if(i<0) returnfalse; LNode*p;//指针p指向当前扫描到的结点 intj=0;//当前p指向的是第几个结点 p=L;//L指向头结点,头结点是第0个结点(不存数据) while(p!=NULL&&j<i)......
  • AWR1243+DCA1000——原始数据中部分chirp采样数据为0
    问题:mmWaveStudio中设置2发4收,帧周期10ms,帧数200,帧中Chirp数为1,ADC采样数512。发现采集的bin文件大小正确,但是部分chirp采样数据为零!解决:尝试加大帧周期;减少采样点;降低dca1000evm里的网络delay参考:[https://e2echina.ti.com/support/sensors/f/sensors-forum/785057/dca1000evm......
  • PHP无法连接MySQL8.0数据库问题处理 报错如下: SQLSTATE[HY000]
    PHP无法连接MySQL8.0数据库问题处理报错如下:SQLSTATE[HY000][2054]Theserverrequestedauthenticationmethodunknowntotheclient发生这种错误,是由于MySQL8默认使用了新的密码验证插件:caching_sha2_password,而之前的PHP版本中所带的mysqlnd无法支持这种验证。解决这个问......
  • 数据库实验课学习笔记2
    约束类型  1.主键约束    语法: 字段  数据类型  primarykey      2.外键约束   语法: foreignkey (字段) references 引用的表(引用的字段)   3.检查约束    语法: 字段  数据类型check(约束内容)  4.默认......
  • 数据库实验课学习笔记1
    数据库与数据表--数据库(文件夹)--数据表(文件)--sqlservermangerment--软件(辅助连接数据库)--navicat等用代码创建数据库   语法:createdatabase 数据库名称createdatabasetext1点击“新建查询”,选中要执行的代码,先点“分析"看你的代码是否有语法错误,......
  • 在Linux中,MySQL数据库日常运维中涉及哪些关键任务?
    在Linux环境下,MySQL数据库的日常运维涉及到一系列关键任务,旨在保证数据库的稳定性、性能和数据完整性。以下是一些核心运维任务:性能监控与调优使用MySQL自身的SHOWSTATUS、SHOWVARIABLES、EXPLAIN等命令,或结合第三方工具(如PerconaToolkit、MySQLEnterpriseMonitor、Prom......
  • 学数据分析 1 年,涨薪10k!教你用Python快速入门数据分析
    现如今,互联网行业的每个人都知道数据的价值,很多人也为此学了一堆的数据分析工具,但面对问题,还是不知道如何去分析。我们在奔向升职加薪的路上,总会遇到这些问题:面对数据问题,没有思路,怎么办?面对一堆数据,该如何下手去分析?面试中的业务问题如何去回答?工作一两年,从岗位本身......
  • 关于SQL假数据生成
     客户端连接手机数量历史记录表:CREATETABLE`xw_client_phone_history`(`id`int(11)NOTNULLAUTO_INCREMENT,`client_user_name`varchar(255)DEFAULTNULLCOMMENT'客户端用户名',`brand_code`varchar(255)DEFAULTNULLCOMMENT'品牌编码',`computer_i......
  • 100_pandas-Python的数据分析包
    目录什么是pandas索引操作赋值和排序算术运算和逻辑运算统计运算自定义函数运算pandas画图文件读取和存储缺失值处理-删除/替换数据离散化数据合并交叉表和透视表分组和聚合什么是pandas索引操作赋值和排序算术运算和逻辑运算统计运算自定义函数运算pandas画图文......
  • 数据库系统概论
    一、引言在信息技术飞速发展的今天,数据已经成为企业和个人决策、研究、生活的重要基础。数据库系统作为数据的存储、管理和检索的核心工具,其重要性不言而喻。本文旨在全面介绍数据库系统的基本概念、发展历程、核心组成、应用领域以及未来趋势。二、数据库系统的基本概念数......