C语言---解析数据在内存的存储

相信大家学过c语言这门科目的都知道和了解我们在存储数据中的一些基本类型。

C语言基本的类型  如:char 字符数据类型、short 短整型、int 整型、long长整型、long long长整型、float 单精度浮点数、double双精度浮点数。当然还有他们所占的存储空间的大小也是有所区分的

我们可以看到不同的类型,存放到内存的方式也是不同的。 

类型的意义:

1.使用这个类型开辟内存空间的大小(大小决定了使用的范围)。

2如何看待内存空间的视角。.

构造类型:数组类型、结构体类型struct、枚举类型enum、联合类型union。

指针类型:int*p、char*p、float*p、void*p、等等。

(void)空类型:通常用于函数返回类型、函数的参数、指针类型。

这些就是我们常用的一些基本类型了。

我们知道为a分配了四个字节的空间,那如何存储?

下来我们 了解下面的概念:

原码、反码、补码

计算机中的有符号数有三种表示方式:即原码、反码、补码。

三种表述方式均有符号位数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方式各不相同。

原码

直接将二进制按照正负数的形式翻译成二进制就可以。

反码

将原码的符号位不变,其他位依次按位取反就可以得到了。

补码

反码+1就得到补码。

正数的原码、反码、补码都相同。

对于整型来说:数据存放内存中其实存放的就补码。为什么呢?

#include <stdio.h>

int mian()
{
	int a=20;
	//原码--00000000000000000000000000010100
	//反码--00000000000000000000000000010100
	//补码--0000 0000 0000 0000 0000 0000 0001 0100
    //16进制0x00000014	 
	int b=-10;
	//原码--10000000000000000000000000001010
	//反码--11111111111111111111111111110101 
	//补码--1111 1111 1111 1111 1111 1111 1111 0110
	//16进制0xFFFFFFF6
	return 0;
 } 

我们通过对概念的理解,正好计算出来,整型在内存中的存储就是通过补码的方式进行存储的。不过可能有细心的同学发现存储的顺序是倒过来存储的,这个我们在下面会为大家进行详细的讲解为什么是倒着存放的。

#include <stdio.h>
int main()
{
	int a=1;
	int b=-1;
	a+b=1-1;
	//1
	//原码--00000000000000000000000000000001
	//反码--00000000000000000000000000000001 
	//补码--00000000000000000000000000000001
	
	//-1
	//原码--10000000000000000000000000000001 
	//反码--11111111111111111111111111111110
	//补码--11111111111111111111111111111111
	
	//原码相加
	//00000000000000000000000000000001
	//10000000000000000000000000000001
	//10000000000000000000000000000010
	
	//补码相加
	//00000000000000000000000000000001
	//11111111111111111111111111111111
	//100000000000000000000000000000000
	//移位
	//00000000000000000000000000000000 
	return 0; 
 } 

在我们对数据进行相加运算时也可以看出,要是我们用原码相加,结果就和我们的答案不一致,所以我们不得不佩服那些研究计算机的伟人们,想到了用补码的型式进行运算并存放,所以当我们用补码进行运算的时候,如代码块所示,结果就和我们的答案相一致了,这也就是为什么整型在内存中的存放是以补码的形式进行存放的了。

我们可以对刚刚的做个总结:

有符号数:正数:原码、反码、补码相同。负数:原码、反码、补码不相同,要进行计算求值。

无符号数:原码、反码、补码相同。

然后我们来讲讲什么时大小端

我们可以看下图:

我们可以看到右图中,从上到下地址是依次增加的,而在我们的左图也可以看出14处于低位,所以分析出来,是低位存放在低地址中,所以是小端存储。

为什么会有大端小端呢?

 下来我们看看2015年百度的一道校园招聘的面试题

概念部分我就不讲解了,因为上面给出了概念,我们主要讲讲实现代码的方面。

我们先来通过一张图来捋清我们的代码思路

我们可以看到假设不知道是大端还是小端存储,我们可以拿20来举例子,要是小端存储在内存中的形式就会是1400000,要是是大端存储在内存中的形式就会是00000014。所以我们就只需要看看前两位的值是不是0就可以知道是大端存储还是小端存储了。(下面为了方便就用a=1来实现)

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


//int check_sys()
//{
//	int a=1;
//	char* p=(char*)&a;
//	if(*p==1)
//	{
//	   return 1;
//	}
//	else
//	
//	return 0;	
//}

//int check_sys()
//{
//	int a=1;
//	char* p=(char*)&a;
//	return *p; 
//}

//int check_sys()
//{
//	int a=1;
//	return *(char*)&a;
//}

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

从编译的结果也可以看出我们是小端存储的,上面代码块中我分别给出了从繁到简的实现过程,作为面试官当然想着是代码写的准确的情况下,代码约简便,就越能展现你的基本功。

不过可能有的同学也会有疑惑为什么在整型a的情况下,我们要去把int型强制转化成char类型,这是因为我们的int型是四个字节,而char型是一个字节的,在指针的解引用操作中,我们用char类型的指针去解引用int型我们就可以只解引用一个字节,只得到我们想要的低位,这样我们就可以通过判断低位的数据,来判断是大端还是小端存储。

 通过上面的解释,相信你对数据在内存中的存放有了一定的了解了,在后面的文章中,我还会对数据的存储做出更深的讲解。

(大学软工在读小白)用来整理我记录我自己的学习日志和收获,如有不对的地方,望各位大佬指出!!!

                 

        

猜你喜欢

转载自blog.csdn.net/m0_59314318/article/details/126044520