相信大家学过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型我们就可以只解引用一个字节,只得到我们想要的低位,这样我们就可以通过判断低位的数据,来判断是大端还是小端存储。
通过上面的解释,相信你对数据在内存中的存放有了一定的了解了,在后面的文章中,我还会对数据的存储做出更深的讲解。
(大学软工在读小白)用来整理我记录我自己的学习日志和收获,如有不对的地方,望各位大佬指出!!!