• C语言 数据在内存中的存储



    正文开始

    1. 整数在内存中的存储

    整数的二进制表示方法有三种:原码、反码和补码
    三种表示方式均由符号位数值位两部分构成。
    符号位,即最高位,用0表示正数,用1表示负数
    数值位,除去符号位剩余的部分都是数值位

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

    负整数的三种表示方法各不相同:

    • 原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码
    • 反码:原码符号位不变,其余为按位取反得到的就是反码
    • 补码:反码 + 1 得到的就是补码

    例如:

    • 十进制数字13,其八位原码、反码、补码都为00001011
    • 十进制数字-13,其八位原码为10001011;反码为11110100;补码为11110101

    对于整数来说,数据在内存中存放的是补码。原因在于,CPU中只有加法器,使用补码可以统一处理加减法,同时也可以将符号位和数值域统一处理。具体的原因请参考这篇文章>>>《原码、反码、补码 详解》,这篇文章思路很清晰。

    2. 大小端字节序和字节序判断

    2.1 何为大小端?

    超过一个字节的数据在内存中存储的时候,就会有存储顺序的问题,就比如十进制数字65224,将其转为二进制数字为1111 1110 1100 1000,存储它进内存,至少需要两个字节的空间,这两个字节存储內容的顺序又产生了分歧。所以我们按照不同的存储顺序,分为了大端字节序存储和小端字节序存储

    • 大端存储模式:数据的低位字节內容保存在内存的高地址处,而数据的高位字节內容,保存在内存的低位地址处。
    • 小端存储模式:数据的低位字节內容保存在內容的低地址处,而数据的高位字节內容,保存在内容的高地址处。

    例如,若一个变量的地址为0×0010,变量的值为0×1122
    那么地址中0×0010为低地址,0×0011为高地址;
    数据中0×11为高位字节內容,0×22为低位字节內容;

    • 大端存储模式中,地址0×0010中存放数据0×11;地址0×0011中存放数据0×22
    • 小端存储模式中,地址0×0010中存放数据0×22;地址0×0011中存放数据0×11

    2.2 为什么需要大小端?

    这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit 位,但是在C语⾔中除了8 bit 的char之外,还有16 bit 的short型,32 bit 的int型,另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就产生了⼤端存储模式和⼩端存储模式

    2.3 字节序判断

    我们可以通过以下程序来判断当前机器的字节序:

    #include 
    
    int check()
    {
    	int i = 1;
    	return (*(char*)&i);
    }
    int main()
    {
    	int ret = check();
    	if (ret == 1)
    	{
    		printf("小端字节序\n");
    	}
    	else
    	{
    		printf("大端字节序\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    解释:
    变量 i 的类型为整型,大小为四个字节,十六进制表示为00 00 00 01。第六行代码中,将指向四个字节的指针强制类型转换为指向一个字节的指针(char 类型大小为一个字节),这样取到了这四个字节在低地址处存放的一个字节,若这个值为1,也就是低位存储在了低地址处,那么就是小端字节序;若这个值为0,也就是高位存储在低地址处,那么就是大端字节序

    运行结果:
    在这里插入图片描述
    请添加图片描述
    从运行结果和内存监视窗口我们也验证了目前我使用的机器是小端字节序。

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

    常见的浮点数:2.453、1E10等,包括float、double、long double类型。我们可以通过查看float.h文件来查看浮点数表示的范围。

    3.1 浮点数的存储

    根据国际标准,任意一个二进制浮点数V可表示为如下形式:

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

    • (-1)S 表示符号位,S=0时,V为正数;S=1时,V为负数
    • M 表示有效数字,是大于1小于2的
    • 2E 表示指数位

    例如:
    十进制的5.0,写成二进制为101.0,标准形式为(-1)0 * 1.010 * 22,也就是说S=0,M=1.010,E=2

    综上所述,我们不难看出,要想存储一个浮点数,只需要存储它的S,M,E,便能得到一个确切的二进制浮点数。

    计算机中,对于32位的浮点数,最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
    在这里插入图片描述
    对于64位的浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
    在这里插入图片描述

    3.2 浮点数存的过程

    国际标准中对于有效数字M和指数E,还有一些特别的规定。

    关于有效数字M
    前面我们说过,有效数组M是一个大于1小于2的数,也就是说M的首位不变,都为1,M都为1.xxxxxxxx的形式。因此,可以将1省略掉,只保留后面xxxxxxxx的部分,这样就多出了一位的空间,也能够正确的存储数据。

    关于指数E
    首先我们要知道,指数E是一个无符号整数,也就是说,E只能表示一个正数,但我们知道,指数也是可以为负数的,那这应该怎么解决呢?
    答案就是,取一个中间值,中间值前面的表示负数,中间值后面的表示正数

    对于8位的E,表示的范围是0-255,我们取中间值为127,也就是说0-126代表着负数,127代表着0,128-255代表着正数。比如当我们想要十次方时,E的值应该为10+127=137,我们想要-3次方,E的值就应该为(-3)+127=124。即10001001;对于16位的E,中间值就为1023。

    3.3 浮点数取的过程

    指数E从内存中取出分为三种情况:

    • E不全为0或不全为1:指数E的计算值减去中间值127(或1023),得到真实值,再将有效数字M前加上第一位的1。
    • E全为0:这时,浮点数的指数E真实值等于1-127(或1-1023),这个数非常非常小了,有效数字M不再加上第一位的1,而是还原为0.xxxxxxxxxx的小数,以此来表示±0,以及接近于0的很小的数字
    • E全为1:这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位S)
  • 相关阅读:
    【windows】网络设置了代理,怎么关闭
    ThreadLocal及InheritableThreadLocal基本原理及注意项
    C++中构造函数什么时候会被调用(从本质上理解)
    深度解读MediaBox SDKs如何实现技术架构升级
    合肥工业大学数据库实验报告
    linux之top、ps、free命令详解
    jenkins系列-07.轻易级jpom安装
    学习笔记:根号分治(优雅的暴力)
    算法篇------动态规划1
    Java基于SpringBoot+Vue的 4S店车辆管理系统
  • 原文地址:https://blog.csdn.net/qq_67140973/article/details/138168661