【C语言】整型和浮点型在内存中的存储方式

欢迎━(*`∀´*)ノ亻!,这里是王_哈_哈 Jw~!!!笑一笑呐!!!


目录

内容提要 :

一.关于数据类型

1.数据类型的基本归类

2.通过sizeof查看各种类型的所占的空间(单位为字节)

二.整型在内存中的存储

1.原码反码补码

2.大小端字节序存储

什么是大小端字节序存储?

 如何判断当前机器的字节序?

方法一(用强制类型转化取出一个字节判断)

方法二(使用联合体):

三.浮点型在内存中的存储

1.一个存储差异的栗子

2.浮点数的存储规则

存储模型

存储细节

S

E

M

例子

从内存中拿出

E不全为0或不全为1

E全为0

E全为1

3.解释前面存储差异的栗子


下面是关于这篇博客分享的内容提要 :

61e29b9d85714762a247caace7c590b2.png


一.关于数据类型

1.数据类型的基本归类

259a8117434c4f50b69ff58dcd53981a.png

(char类型本质上是以它的Ascall码值存储的,所以归类到整型。)

2.通过sizeof查看各种类型的所占的空间(单位为字节)

C语言中没有明确规定long的大小,但sizeof(long)一定大于等于sizeof(int)

char占1Byte,8bit!int占4Byte,32bit!float占4Byte,32bit!

94e4282902a044658d07579a5e157f53.png


二.整型在内存中的存储

整数在内存中存的是它的补码

1.原码反码补码

原码反码补码是整数的三种表示方法,它们的第一位为符号位(0表示正,1表示负),其余为数值位。原码就是将该整数按正负数的形式直接翻译成二进制。

正数的原反补码相同。

负数的反码:符号位不变,其余位按位取反;补码:反码+1;

例如:

10 

原码:0000 0000 0000 0000 0000 0000 0000 1010

反码:0000 0000 0000 0000 0000 0000 0000 1010

补码:0000 0000 0000 0000 0000 0000 0000 1010

-10

原码:1000 0000 0000 0000 0000 0000 0000 1010

反码:1111 1111 1111 1111 1111 1111 1111 1111 0101(符号位不变,其余位按位取反)

补码:1111 1111 1111 1111 1111 1111 1111 1111 0110(反码+1)

所以当我们在运行

int main()
{
    int a = 10;
    int b = -10;
    return 0;
}

这样一段代码时,计算机在内存中就开辟了两个4字节的空间分别存放a和b的补码。

0f2ff7a9edaf431a85f179904a56e1cc.png

(实际上当我们在编译器上进行调试查看内存时为了方便展示,显示的是十六进制的数值)所以理论上当我们查看内存时应该是这样的:

8a96708c98e345909bdc3377e16ca8b1.png

 但实际上当我们打开vs,输入这段代码,在进入F10调试后,点击调试-->窗口-->内存 分别输入了&a,&b,并将列数改为4看到的结果是:

a45a16e2c1a34785b423f69820ffbb4f.png

 发现每个字节的顺序与我的理论正好颠倒,这是由于计算机的大小端字节序存储的原理。

2.大小端字节序存储

什么是大小端字节序存储?

字节序:以字节为单位的存储顺序。(C语言的数据存储是以字节为单位的,每个地址单元对应一个字节即8bit)。

大端存储模式:数据的低位保存在内存的高地址;

小端存储模式:数据的高位保存的内存的低地址。

cf24f4a1f07a41c19b8235c3ac5a0eba.png

 (对于一个32bit的十六进制数0x11223344来说,11是高位,44是低位)

 如何判断当前机器的字节序?

(我们常用的x86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式,有些ARM处理器还可以用硬件来选择是小端还是大端)

方法一(用强制类型转化取出一个字节判断)

(我们可以用一个程序实现判断:我们创建一个int类型的i,放入一个1,把他转化为正常的十六进制就是0x 00 00 00 01,内存中一个字节一个字节地存储,如果是大端:0x 00 00 00 01,小端:0x 01 00 00 00. 接着我们把本来为int*类型的&i强制类型转化为char*并解引用的值返回,如果是大端就是ox00=0,小端即为0x01=1)

int check_sys()
{
	int i = 1;
	return(*(char*) & i);    //将&i强制类型转化为char*
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

bb304a52f5f34adaa9693672c8527816.png

方法二(使用联合体):

(因为联合体内的数据占的是一块内存,下面这个联合体的内存大小为4个字节,c正好在低字节处,如果是小端存储01和char占同一块内存就会返回1,反之和上面原理一样。)

int check_sys()
{
	union
	{
		int i;
		char c;
	}un;
	un.i = 1;
	return un.c;
}

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

4bc2e0713f394a6b9fb1b43897e6efd4.png


三.浮点型在内存中的存储

我们常见的浮点数有3.14,1E10(1.0*10^10)等,常见类型有float,double,long double。它们的表示范围在float.h中定义。浮点数在计算机中也用二进制形式存储,但和整型大相径庭。

1.一个存储差异的栗子

(这里不是把浮点数和整数相互强制转换,而是将他们分别用对方的存储方式解释并打印)

57f4b330646c461ca9a99832e6580cee.png

 当我们把整型9用浮点数存储方式解释之后变成了0.000000,而9.0用整型存储方式(补码)解释之后变成了一个很大的数字,就很六。那么浮点数到底是咋子存储的嘞(色.jpg)

2.浮点数的存储规则

存储模型

根据国际标准IEEE(电器和电子工程协会)754,任意一个二进制浮点数V可以表示成下面形式:V=(-1)^S*M*2^E

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

例如:

  • 十进制的5.5写成二进制为101.1 如果用以上方式表示:(-1)^0*1.011*2^2 。此时S=0,M=1.011,E=2
  • 十进制的0.5写成二进制为0.1   →  (-1)^0*1*2^(-1).此时S=0,M=1,E=-1

对于一个32位的浮点数,它的存储模式如下图(对于一个64位的浮点数E占11bit,M占52bit):

b76b4f4ba1ef492fbee9ce381c7c0fb5.png

存储细节

S

S存储比较简单,在第一位,正数为0,负数为1.

E

E代表的是指数(二进制的科学计数法,咱可以理解为小数点向哪边移动了多少位,向左移动两位是2,向右移动两位就是-2),实际上是有正有负的,但是E是一个无符号整数(unsigned int)。如果是8位的E,取值范围就是0~255;如果是11位,取值范围0~2047.

为了能够表示正负,IEEE754规定,存入E的真实值必须再加上一个中间数,对于8位的E,这个中间数为127,对于11位的E中间数为1023。比如

5.5的表面E值为2,实际E=2+127=129,即10000001.   

0.5的表面E值为-1,实际E=(-1)+127=126,即01111110.

M

因为M大于等于1小于2,就是1.xxxxxxx,。IEEE754规定反正这个个数一直为1,就不保存,只保存xxxxxxx,所以保存5.5(101.1)时,M=1.011,实际上保存的是011(前面20位补0)

例子

103bfd3399af45588a077d058eadbf29.png

从内存中拿出

分三种情况,S表示正负

E不全为0或不全为1

将指数E减去127(或1023),得到真实值,再将有效数字M前加上第一位的1

E全为0

指数E=1-127(或1-1023),得到真实值,有效数字M不再加上第一位的1

(如果E全为0的话,说明原来的指数为-127,说明0.00000(126个0)1,就是一个趋于零的数字,正负取决于S)

E全为1

这时,如果有效数字M全为0,表示正负无穷大

3.解释前面存储差异的栗子

1.用浮点数的存储方式解释整数9

int n = 9;内存中是这样的(以9的补码存储):

00000000000000000000000000001001

float* pf = (float*)&n;(我们给计算机洗脑,说这块内存是以浮点数形式存的,所以)

计算机把它分成SEM三部分,第一个0代表正数,后八个为E都是全为0,直接得出0.000000(%f默认六位小数)

2.用整数的存储方式解读浮点数9.0

float i = 9.0;(根据浮点数的存储规则,内存上是这样的:)

0 10000010 00000000000000000000001

int* pi = (int*)&i;(我们给计算机洗脑这不是以浮点数存储方式存储的,是一个补码,所以)

它是一个正数直接转化为十进制,就是刚刚运行出来的结果

79a3767a3baa476ab8932e1b1d40f05b.png


好啦~以上就是这次分享记录的全部内容,真切体验到创作不易了,呜呜呜~我还要还得再改进改进。谢谢支持,谢谢自己~

点个赞赞叭~~

42e4a8dbb7db42d8ab3df0432ce7647d.jpegba6a0afc17a24fba8fbc25fe77a6e929.jpeg4efd6403058541bdaf43305bc9e79d98.jpeg

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王_哈_哈 Jw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值