数据在内存中的存储

什么是内存? 在计算机的组成结构中,有一个很重要的部分,就是存储器。存储器是用来存储程序和数据的部件,对于计算机来说,有了存储器,才有记忆功能,才能正常工作。存储器的种类很多,按其用途可分为主存储器和辅助存储器,主存储器又称内存储器,简称内存。
内存,被分为一个一个的内存单元。一个内存单元我们通常规定放一个字节。

数据类型的详细介绍
数据类型分为:内置类型和自定类型
数据类型的意义:(1) 使用这个类型开辟内存空间的大小
(2) 决定了我们如何看待内存空间的视角
类型的基本归类:
1.整型家族:char short int long
2.浮点型家族:float double
3.构造类型:数组类型,结构体类型struct,枚举类型enum,联合类型union
4.指针类型 int *pi,char *pc,float *pf,void *pv
5.空类型:void表示空类型(无类型),通常应用于函数的返回类型,函数的参数,指针类型
数据在内存中的存储
数据在内存中的存储形式是二进制形式。
但VS在展示内存的时候,为了方便展示,显示的是16进制数据。

有符号的整数 - 符号位 + 数值位
正数: 0 + 数值位
负数: 1 + 数值位
对于正数来说:原码反码补码都相同
对于负数来说:
原码 - 直接根据正负数值给出二进制序列
反码 - 原码的符号位不变,其他的按位取反
补码 - 反码二进制最低位+1
如下代码举例:

int main()
{
    int a = 3;
    //00000000 00000000 00000000 00000011 - 原反补

    int b = -1;
    //10000000 00000000 00000000 00000001 - 原码
	//11111111 11111111 11111111 11111110 - 反码
	//11111111 11111111 11111111 11111111 - 补码 
    return 0;
}


如上图,我们发现,尽管数据在内存中的存储形式是2进制形式,但为了方便展示,VS在展示的时候,显示的是16进制。
且发现,对于整数来说,在内存中存放的是补码。
为什么会是补码呢?
我们知道,CPU加法器运算加减乘除,是在加法的基础上,进行的。这里举例减法。

int main()
{
	int c = 1 - 1;
	//计算机会自动转化成加法:1-1  ----> 1+(-1)
	return 0;
}

我们发现,用原码进行计算时,得到的是-2,不符合减法运算。而聪明的程序员想到,用补码试一试是否可行呢?答案是正确的。使用补码,可以将符号位和数值域统一处理。补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

得知在VS编译器的内存窗口中,数据存储的地址不仅显示的是16进制形式,存放的是形式还是补码。那么补码存储的顺序是什么呢?
我们不妨创建一个十六进制的数据,一探究竟。

int main()
{
	int c = 0x11223344;
	return 0;
}

我们在VS中,调试-窗口-内存中发现,顺序是倒着存放的!在这里插入图片描述
那么为什么是倒着存的呢?这里将要引入一个概念-大小端字节序
大端字节序存储:把一个数的低位字节序内容放在高地址处,把高位字节序内容放在低地址处。
小端字节序存储:把一个数的低位字节序内容放在低地址处,把高位字节序内容放在高地址处。
由上述可见,当前机器采用的是小端存储。

写一个代码,判断当前机器是采用大端还是小端

int main()
{
	int a = 1;//00 00 00 01
	char*p = (char*)&a;//强制类型转换 只会转换类型 值不会发生改变
	if (*p == 1)
	{
		printf("小端\n");
	}
	else printf("大端\n");
	return 0;
}

注:此处如果采用另一种强制类型转换:char c = (char)a 是不正确的,因为只取了a的最低的那个字节,也就是1。违背了我们想要取第一位字节的目的。

探讨某类型的存储范围,用signed char类型举例:
在这里插入图片描述

正数是[0,127],负数是[-1,-128]
所以signed char的存储范围是[-128,127]
直观表示:
在这里插入图片描述

同理,也不难推出unsigned int 的存储范围是[0,255]

例题1举例:

int main()
{
    char a = -1;
    signed char b = -1;
	unsigned char c = -1;
	printf("a=%d b=%d c=%d\n", a, b, c);
    return 0;
}

运行结果如下:
在这里插入图片描述
现做如下分析:
a和b的结果一样,说明当前编译器认为char 就是 signed char。
a - 11111111 11111111 11111111 11111111 - 补码
char只存8个bit位 所以只拿11111111
所以a的内存里存储的就是8个1
同理,b和c也存的都是11111111。abc内存里存的都是一样的
要求%d打印,打印的是整数,所以要进行整型提升,按照原符号位提升(对于有符号的a和b来说)
提升之后 11111111 11111111 11111111 11111111
转成原码 10000000 00000000 00000000 00000001
所以a和b打印出来是-1
因为c是无符号位,整型提升时最高位的1不是符号位了,它是有效位,这时只能补0。
00000000 00000000 00000000 11111111
最高位是0,是正数。正数的原反补都是一样的。
所以原码也是这个。所以c打印出来是255。

例题2举例:

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

运行结果如下
在这里插入图片描述
现做如下分析:
(1)先写出-128的原码:
10000000 00000000 00000000 10000000
反码 - 11111111 11111111 11111111 01111111
补码 - 11111111 11111111 11111111 10000000
因为char类型只取8个bit位,所以只拿10000000,即a中所存就是10000000。
(2)%u形式打印,所以要做整型提升。提升的时候要看这个数原来的符号位,它是char类型,有符号的char类型。也就是要补1。
整型提升后的补码:
11111111 11111111 11111111 10000000
(3)%u认为它是无符号的数,所以原反补都是一样的。所以打印的数就是该原码的十进制数字。
而我们知道1 00000000 00000000 00000000 00000000是2的32次方,所打印的数与它相差1111111再加1。也就是相差128。所以打印后所得(2的32次方-128)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值