数据在内存中的存储(超详解)

目录

引言

 1.  大小端顺序

1.1 定义

1.2 检验的方法

1. 调试

2.  代码

2. 整型在内存中的存储

3. 字符及数组在内存中的存放 

3.1 字符

3.2 数组 

4. 浮点数在内存中的存放 

4.1 存放规则 

4.2 举例 

 4.3  读取规则

4.3.1 E不全为0或不全为1

4.3.2 E全为0或全为1 

5 练习


引言

c语言常用的内置数据类型有整型,字符型,浮点类型,研究他们的存储方式虽然不能直接帮助我们提高代码能力,但也好比修炼内功,一定会使我们对程序更有“掌控感”.接下来,我们将从大小端顺序到整型,字符型,最后到浮点类型,为大家分享数据在内存中的存储等相关问题。

 1.  大小端顺序

1.1 定义

我们都知道,计算机访问数据一般都是以字节为单位的,一个字节包括8个比特位,可以存储256个不同的数据。但如果是超过了一字节的数据1,通常就设计到了大小端的顺序,比如十六进制0x11223344在内存中的存放。

所谓大端排序,就是高字节的部分(11),放在低地址处,低字节的部分(44),放在高字节处。

 所谓小端排序,就是高字节的部分(11),放在高地址处,低字节的部分(44),放在低地址处。

1.2 检验的方法

 在不同的编译器下,可能会采取不同的排序方式。那么如何查看呢?这里有两种方法供大家思考。

1. 调试

 可以通过调试,调用内存窗口,如在vs2022,x64的环境下,int类型的储存就是小端排序的。

2.  代码

#define _CRT_SECUR_NO_WAENINGS 1
#include<stdio.h>

int check(int* p)
{
	return *((char*)p);
}

int main()
{
	int x = 1;
	int ret = check(&x);
	if (ret)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}

	return 0;
}

计算机中每个字节都有一一对应的地址,而超过1个字节的数据,比如int,4个字节,取出的地址是地址最小的那个,也就是低地址。

我们可以取出x(1),再强制类型转换成char*,再解引用,我们就可以得到数据在低地址处的值,1的值高字节位00,低字节位01,解引用出来,是哪个,就是哪个。

2. 整型在内存中的存储

整型在内存中存放数据时都是以二进制的补码进行存储的。有符号无符号都一样的

如 -666在内存中的存储

原码:0000 0000 0000 0000 0000 0010 1001 1010

反码:1111 1111 1111 1111 1111 1101 0110 0101

补码:1111 1111 1111 1111 1111 1101 0110 0110

十六进制:0xFFFF FD66

小端存放: 66 FD FF FF

3. 字符及数组在内存中的存放 

3.1 字符

字符在内存中的二进制的值在ASCII 码表 - cppreference.com中变可以查到。

字符‘a’的ASCLL值为97

97 的16进制为61

左边表示的是值,右边表示的是对应的ASCLL字符

3.2 数组 

我们需要记住,数组中的成员在内存中是由低地址到高地址连续存放的

如“abcdefg”,a在低地址,g在高地址

4. 浮点数在内存中的存放 

4.1 存放规则 

这是浮点数在内存中存储的标准。

4.2 举例 

 比如浮点数-173.8125

// 转换成二进制(整数部分:除2取余,逆序排列,小数部分:乘2取整,顺序排列

二进制为:-1010 1101.1101

// 二进制101(6)= 1.01 * 2^2 前面是二进制,后面是十进制表示,这样做,是为了方便

// 因为我们要的就是他的指数位,指数位其实就是小数点移动的位数

转换成科学计数法-1.010 1101 1101 * 2^7 

由于是负数: (-1)^1 * 1.010 1101 1101 * 2^7

S = 1

M = 1.010 1101 1101

E = 7

 单精度32位浮点数float

双精度64位浮点数double

以上便是浮点数在内存中的存储排序方式,也就是我们的S,M,E的排列存放方式。由低地址到高地址分别是S,M,E。

关于M

在科学计数法中M一定是1.xxxxx,不要觉得0.8125就会0开头了,二进制为0.1101,转换后就是1.101 * 2 ^-1,M就是1开头的。——因次默认这个数的第⼀位总是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。

-173.8125    S,M,E  转换1 1000 0110 010 1101 1101 000000000000

1100 0011 0010 1101 1101 0000 0000 0000

C3 2D  D0 00

小端排序后 :00 D0 2D C3

 4.3  读取规则

4.3.1 E不全为0或不全为1

正常翻译即可。

调试看到:00 D0 2D C3

换位置:C3 2D D0 00

展开:1100 0011 0010 1101 1101 0000 0000 0000

S = 1        M = 1.010 1101 1101        E = 7

值= -173.8125

4.3.2 E全为0或全为1 

如果E全为0,这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还 原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字。

如果E全为1,这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);

5 练习

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

结果:

n的值为:9
*pFloat的值为:0.000000
num的值为:1091567616
*pFloat的值为:9.000000

评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值