数据在内存中的存储

1.整数在内存中的存储

整数的二进制表示方法有三种:原码,反码,补码。

有符号的整数:三种表示方法均有符号位和数值两部分,符号位都是用0表示"正",用“1”表示“负”最高位的一位是被当做符号位,剩余的都是数值位。

正整数的原,反,补码都相同。

负整数的三种表示方法各不相同。

对于整形而言:数据存放内存中其实存放的是补码。 

为什么呢?

2.大小端字节序和字节判断 

当我们了解了整数在内存中的存储, 我们来调试一个细节。

 #include <stdio.h>
 int main()
 {
 int a = 0x11223344;//这里是十六进制的数字
 //11两个十六进制位就是八个二进制位,就占一个字节
//所以说这串十六进制数字就占四个字节,所以这串就正好把n填满。
 return 0;
 }

调试的时候,我们可以看到a中的0x11223344这个数字是按照字节为单位,倒着存储的,这是为什么?

这就涉及到大小端了。

2.1什么是大小端?

大端存储(Big-endian)和小端存储(Little-endian)是两种不同的数据存储方式,它们描述的是多字节数据(如整数、浮点数等)在内存中的字节顺序。

其实超过一个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为大端字节和小端字节存储,下面是具体的概念:

大端(Big-Endian):最高有效字节(Most Significant Byte, MSB)存储在最低的内存地址上。也就是说,数据的高位字节先存储,低位字节后存储。这种存储方式在人类阅读习惯上比较直观,因为数字的高位通常更重要。
小端(Little-Endian):最低有效字节(Least Significant Byte, LSB)存储在最低的内存地址上。也就是说,数据的低位字节先存储,高位字节后存储。这种存储方式在计算机内部处理时更为高效,因为CPU处理数据时通常是从低地址开始的。

 2.2为什么有大小端?

练习:

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。

首先我们需要考虑一个事情,关于大端小端我们怎么区分?假设是1这个数字他的十六进制是

0x00 00 00 01他的大端存储就是00 00 00 01,小端就是这样01 00 00 00。如果我把大端小端的字节都拿出来的话进行比较一个是1一个是0。这样不就可以比较了。 那接下来具体的步骤我会在代码中进行讲解:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int n = 1;
	if (*(char*)&n = 1)//首先这里的&n就是取出n的首地址,把n的首地址转换成char*的类型,
//变成一个字节,在进行解引用就会得到n的第一个字节的元素
//接下来进行打印
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

那这个里面为什么不能写成这样的char c = (char)n;?因为做不到,假如说n = 0x11223344你把n强制类型转换成char类型的 ,把一个大的类型转化成一个小的类型都是取低地址出的,也就是不管是11223344还是44332211取出来都是44。

 那如果我们把他封装成一个函数怎么弄呢?

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int check_sys()
{
	int n = 1;
	return (*(char*)&n);
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf(" 大端\n");
	}
	return 0;
}

就是这样。 

练习:

这个的结果是什么?

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

这里我们是不是有些疑问?为什么char是字符型的但是为什么可以赋值为一个整数? 

因为会发生截断,我会在代码中进行讲解并讲解为什么会打印出这个结果:

#include <stdio.h>
int main()
{
 char a= -1;
//-1的二进制序列是这样的
//10000000000000000000000000000001 -1的原码
//11111111111111111111111111111110 -1的反码
//11111111111111111111111111111111 -1的补码
//但是char只能存8个比特位,所以会发生截断
//取出的就是最后的八位
//为什么是最右边的八个,因为最有效的就是最右边的。
//11111111  a的二进制序列
 signed char b=-1;
//11111111  b的二进制序列
 unsigned char c=-1;
//11111111  c的二进制序列
 printf("a=%d,b=%d,c=%d",a,b,c);
//但是这里的a,b,c都是用%d来进行打印的,但是现在的abc还都是字符型的,都是八个比特位,所以要进行整型提升,我们要知道整型提升要补符号位,所以a补完就是这样的11111111111111111111111111111111。
//现在这个全1是内存的补码,我们要转换成原码进行打印最后就是10000000000000000000000000000001所以a打印出来就是-1
b同理
但是c就不一样了c是unsigned char他的11111111的最高位不是符号位所以整型提升完之后是这样的
//0000000000000000000000011111111而现在最高位就是0,原码反码补码都相同,现在这个打印出来就是255
 return 0;
}

在这个练习中你有没有疑惑这一点,就是打印的时候为什么要转换成原码进行打印,但是他明明在内存中存储的是补码?这里给出解释:

我们这个数据存储在计算机中是以补码的形式去存储,然后我们要打印的时候会转化成对应的源码去展示的;这句话可以理解成规定的

这就是unsigned char的取值范围的解释:

这就是signed char的范围解释:

练习:
#include <stdio.h>
int main()
{
 char a = -128;
 printf("%u\n",a);
 return 0;
}

首先先解释一下%u是打印什么的:%u 十进制无符号整数 ,那现在我们是不是就会懂得了。
 我还会在这个代码中进行讲解:

#include <stdio.h>
int main()
{
 char a = -128;
//10000000000000000000000010000000   -128的二进制序列原码
//11111111111111111111111101111111   -128的反码
//11111111111111111111111110000000   -128的补码
 printf("%u\n",a);
又因为a是char类型的所以要取最后八个10000000但是要用%u进行打印所以要进行整型提升又因为是char在vs里面是有符号的,这时候就补最高位符号位结果就是:
//11111111111111111111111110000000,进行整型提升完我们要用%u进行打印所以最高位不是符号位,结果就
//是一个很大的数。
 return 0;
}

讲解完毕可供参考,这里我要进行一点说明,如果要进行整型提升的话,要看这个变量的类型,看看是不是有符号的,如果是有符号的话:看看最高位是啥就补啥;如果是无符号的那么即使这个数是个负数,最高位也不会当成符号位,补的就是0。

练习:
#include <stdio.h>
int main()
{
 char a = 128;
 printf("%u\n",a);
 return 0;
}

 这个串代码和上面差不很多,可以尝试理解,我也会在代码中进行说明讲解:

#include <stdio.h>
int main()
{
 char a = 128;//这里就是和上面代码的不同点我们据徐来看一下:
//00000000000000000000000010000000  这里就是128的原码反码和补码
//10000000 这里就是a的二进制序列
 printf("%u\n",a);
//这里我要对a进行%u的打印,所以我们要对a进行整型提升,我们看一下a的类型,是char类型他是有符号的。
//所以a的最高位就是符号位a就是这样的:
//1111111111111111111111110000000这就是整型提升完a的二进制序列,但是关于最高位是不是符号位我们呢还是要看一下占位符,%u打印无符号的整数。
//最后打印出来就是上面代码的结果
 return 0;
}

为了更清晰的了解这个问题我们来看一下对比:

我们通过这位一点能看出来,unsigned char不管等于128还是-128打印出来都是128这说明他不在乎你最高位是不是符号位。反正就是无符号。整型提升就是加的0.

而char类型的不管是-128还是128打印出来都是那个大的数字,因为他们整型提升都是加的1,但是最什么最后打印出来都是正数呢,因为有%u不管最高位了,反正就是无符号,最高位就是数值位。

OK了兄弟们是时候说再见了,今天完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值