深度理解数据在内存中的存储

目录

一,类型介绍

二,数据储存的大小

整型,浮点型

指针

枚举型

三,存储方式

整型

浮点型


一,类型介绍

在C语言中,常用的数据类型有7种

内存占用大小/Byte
char字符数据类型1
short短整型2
int整型4
long长整型4
long long长长整型8
float单精度浮点型4
double双精度浮点型8

 类型归类:

整型家族浮点型家族指针家族构造家族空类型
char

unsigned char

signed char

float整型指针(char*,int*...)structvoid

short

unsigned short

signed short 

double浮点型指针(float*,double*)enum
int

unsigned int

signed int

结构体指针(eg:struct s*) union
long

unsigned long

signed long

空指针(void*)数组
long long

unsigned long long

signed long long

数组指针(eg:int (*a)[2] )

好了,我们大概知道了数据的类型,那么这些数据的类型在内存中是如何存储的呢?存储的大小是怎么样的呢?我们用代码一探究竟吧。


二,数据储存的大小

整型,浮点型

第一个表中有写到,常用类型的存储大小,那么我们用代码验证一下:

此外,那么其他类型的存储大小是多少呢?我们再用代码验证一下:

指针

32位状态:                                                             64位状态:

 可以看到,不同状态下的指针,大小也不同,且无论什么类型,都是一样的大小,

由此可得:指针的大小只与平台大小有关

32位64位
4byte8byte

枚举型

枚举型的存储大小在C语言中默认是4个字节,一个整型的大小。如下图(vs2022):

类型大小(byte)
enum4

值得注意的是:如果赋给的值大于2^32-1则会产生截断

由于结构体,联合体的内存占用不是固定值,有内存的对齐方式,所以在下篇博客进行介绍。

三,存储方式

我们知道了数据在内存存储的大小,也知道计算机是一01的二进制位进行计算的,但是数据在内存里是如何存放的呢,他们之间又有什么关系呢,下面我们来一一探解。

关系:任何数据在内存中都是以二进制的形式存储的。

整型

呈现方式:原码呈现

存储方式:补码存储,补码计算,以原码来打印

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

例子:

(内存里以16进制显示)

 我们用几道题来加深一下对他们的存储方式的理解

下面程序输出什么:

1.

#include <stdio.h>
int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("a=%d,b=%d,c=%d", a, b, c);
	return 0;
}

2.

int main()
{
	char a = -128;
	printf("%u\n", a);
	return 0;
}

3.

int main()
{
	char a = 128;
	printf("%u\n", a);
	return 0;
}

4.

int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%d\n", i + j);
	return 0;
}

5.

int main()
{
	unsigned int i;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
	}
	return 0;
}

6.

int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
	return 0;
}

7.

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

题解1.

 2.

3. 

  4.

 5.

6.

 

 7.

以上解题方法都是依照编译器底层工作逻辑来计算的,其实像第四题,只要数值不超过类型的规定范围,就可以按照直接相加减来计算

 好了,我们知道了整型在内存里是一二进制补码的形式存储和计算的,以原码的形式打印的,那么浮点型又是如何呢?是否一样,让我们继续了解。

浮点型

浮点型的存储有公式可循:(-1)^S*M*2^E

十进制二进制公式化S,M,E
5.5101.1(-1)^0*1.011*2^2S = 0,M = 1.011,E = 2
10.251010.01(-1)^0*1.01001*2^3S = 0,M = 1.01001,E = 3
-7.75111.11(-1)^1*1.1111*2^2S = 1,M = 1.1111,E = 2

因为在小数部分中,十进制转换为二进制存在不精准的情况。所以有些浮点型小数在内存无法精确保存。

得到S,M,E后,则内存就对此进行对应存储。

在存储之前,IEEE 754规定:

  • 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
  • 因为E可以取负数,所以规定在加一个修正值,32位平台下E加上127,64位平台下E+1023,确保E+127/1023在内存里存储的为无符号数。

存储规则如下:

(32位平台下E+127)

S(1bit)E(8bit)+127W(23bit)
5.5(S = 0,M = 1.011,E = 2)01000000101100000000000000000000
-7.75(S = 1,M = 1.1111,E = 2)11000000111111000000000000000000
10.25(S = 0,M = 1.01001,E = 3)01000001001001000000000000000000

 我们可以验证一下:

由于vs2022内存是小端存储,所以

内存存储方式
5.50100 0000 1011 0000 0000 0000 0000 000040 B0 00 0000 00 B0 40
-7.751100 0000 1111 1100 0000 0000 0000 0000C0 FC 00 0000 00 FC C0
10.250100 0001 0010 0100 0000 0000 0000 000041 24 00 0000 00 24 41

注意:E全为1和全为0的两种特殊情况

00000000E取-126,M取.xxxx,该浮点数大小为0
11111111该浮点数大小为正/负无穷级数

 好的,以上浮点型的存储规则就介绍的差不多了,我们来道题巩固一下知识点。

//打印的数是什么
int main()
{
	int a = 10;
	float* pa = (float*) & a;
	printf("%d %f\n", a,*pa);
	*pa = 10.25;
	printf("%d %f\n", a, *pa);
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值