数据在内存中的存储(详细版)


1、整型在内存中的存储

(32位系统)spa

在VS2013中,使用调试->窗口->内存,来观察内存的具体状况。
在这里插入图片描述
让咱们经过内存窗口来看看整型在内存中的存储,
定义一个整形变量int a= 10;


翻译


注意:能够在地址栏中使用&来找到目标变量的内存状况。
在这里插入图片描述
3d


a的地址:0x00EFF980
在这里插入图片描述
调试

int型在内存中是以4个字节为单位存储的,内存中用16进制表示。能够看到a的值为0a(16进制),换算成十进制就是10。code


一、字节序

为何会有大小端模式之分呢?blog

    这是由于在计算机系统中,咱们是以字节为单位的,每一个地址单元都对应着一个字节,一个字节为8bit。可是在C语言中除了8bit的char以外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,因为寄存器宽度大于一个字节,那么必然存在着一个若是将多个字节安排的问题。所以就致使了大端存储模式和小端存储模式。图片

(1)小端字节序

小端(存储)模式:
数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。

内存

咱们输入一个十六进制数,来观察一下在内存中的状况开发

int a = 0x11223344

在这里插入图片描述能够看到高位11保存在内存的高地址中,低位44保存在内存的低地址。编译器

(2)大端字节序

大端(存储)模式:
数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。

int a = 0x11223344;

以上例子在大端字节序中的存储是这样的:
在这里插入图片描述在平常生活中,大部分的pc都是使用小端字节序。

(3)写一个程序判断是否为大端字节序

规定:返回0不是,返回1是。

#include <stdio.h>
int isBigEnd(int a) { 
	int* p = &a;
	char* p2 = (char*)p;
	if (*p2 == 0x11) { 
		return 1;
	}
	return 0;
}
int main()
{ 
	int a = 0x11223344;
	printf("%d\n", isBigEnd(a));
	system("pause");
	return 0;
}

二、原码补码反码

计算机中的符号数有三种表示方法即原码、补码、反码。正数的原、反、补码都相同。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同。

原码:直接将二进制按照正负数的形式翻译成二进制就能够。

反码:将原码的符号位不变,其余位依次按位取反就能够获得了。

补码:反码+1就获得补码。

(1)补码

对于整形来讲:数据存放内存中其实存放的是补码。
-10在内存中的存储:
在这里插入图片描述在内存中咱们能够看到在内存的存储的值为 f6 ff ff ff 。

在上面已经为你们介绍了小端字节序,由于个人计算机是小端字节序。
因此它的值就为ff ff ff f6。

用二进制的方式表示:
1111 1111 1111 1111 1111 1111 1111 0110
-10的原码:
1000 0000 0000 0000 0000 0000 0000 1010
-10的反码:
1111 1111 1111 1111 1111 1111 1111 0101
-10的补码(反码+1):
1111 1111 1111 1111 1111 1111 1111 0110






能够看到和上面ff ff ff f6转换成二进制的结果相同。

(2)补码的意义

为何对于整形来讲,数据存放内存中其实存放的是补码呢?

   数据存放内存中其实存放的是补码在计算机系统中,数值一概用补码来表示和存储。缘由在于,使用补码,能够将符号位和数值域统一处理;同时,加法和减法也能够统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不须要额外的硬件电路。

补码存在的意义就是让硬件实现简单

好比:把负数按补码表示,能够统一±为+。
例子:
1-10=1+(-10)
在这里插入图片描述




在这里插入图片描述

2、浮点型在内存中的存储

一、浮点型

根据国际标准IEEE(电气和电子工程协会),任意一个二进制浮点数V能够表示成下面的形式:
(-1)^S * M * 2^E
(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。
举例来讲:
十进制的5.0,写成二进制是101.0,至关于1.01×2^2。 那么,按照上面V的格式,能够得出s=0,M=1.01,E=2。
十进制的-5.0,写成二进制是-101.0,至关于-1.01×2^2。 那么,s=1,M=1.01,E=2。






IEEE 754规定:
对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。在这里插入图片描述

对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
在这里插入图片描述

M占用的比特位越多,数据精度越高。
E占用的比特位越多,数据范围越大。
因此在实际开发中使用double较多。

二、浮点数的比较

使用这种方式来存储的时候,会带来一个很大的问题,保存的小数每每不是一个精确值,而只是一个近似值。

示例:

#include <stdio.h>
int main()
{ 
	float a = 11.0;
	float b = a / 3.0;
	if (b * 3.0 == a) { 
		printf("相等!\n");
	} else { 
		printf("不相等\n");
	}
	system("pause");
	return 0;
}

实际上11.0/3.0*3.0确定等于11.0。
可是咱们看看运行结果:
在这里插入图片描述因此,浮点数在内存中存储的时候,不少时候是有偏差的。


正确的比较方法:

使用作差的方法,而后判断差值是否是在容许偏差范围内,若是在的话,就相等。

#include <stdio.h>
#define N 1e-4
int main()
{ 
	float a = 11.0;
	float b = a / 3.0;
	if (b * 3.0 - a < N && b * 3.0 - a > -N) { 
		printf("相等, 此处不是严格相等, 而是容许偏差\n");
	} else { 
		printf("不相等\n");
	}
	system("pause");
	return 0;
}

在这里插入图片描述

相关文章
相关标签/搜索