这里首先说一下字节序的概念:
我个人理解为数据以二进制在计算机内存中储存的顺序。
字节序分为两种:大端和小端
大端:低地址储存高位
例如:int a=1;此时a在32位系统中的储存形式为 00 00 00 01(前面是低位,后面是高位)
小端:低地址储存低位
例如:int a=1;此时a在32位系统中的储存形式为 01 00 00 00
这里简要说明一下网络字节序与主机字节序
网络字节序是不同主机之间传输数据时用的,同一规定为大端字节序。
主机字节序则相反,为小端字节序。
如何分辨自己的字节序:
可使用一段代码来分辨:
int main()
{
union{
char a;
int b;
}Test;
Test.b = 0x01000002;
printf("%X\n", Test.a);
}
a和b的起始地址一样,a只占1个字节,而b占4个字节,当用%X以16进制输出a时,此时a输出的是b的低地址,如果输出为1,则低地址存高位,是大端字节序,如果输出为2则是小端字节序。
在讲数据存储前要了解一个概念:类型转换。类型转换分为显式类型转换和隐式类型转换,
显式类型转换是由程序员明确指定的,也被称为强制类型转换。
隐式类型转换是由编译器自动进行的,我们无法观察到。
隐式类型转换有整形提升和运算转换
整形提升:
小的数据类型存入大的数据类型时前面要补位
例如char类型存入int类型时前面要补位,补位也分情况:
如果是有符号数,前面补最高位。
(在内存里数据是以补码形式储存的,所以要补最高位)
如果是无符号数,前面补0。
运算转换:
例如:
int main()
{
int a = 1;
unsigned int b = 2;
if ((a - b) > 0)
{
printf("Yes\n");
}
else{
printf("No\n");
}
}
以上代码的结果输出为Yes,也就是说(a-b)的结果本来是-1,但是被 强制转换成了无符号数,
-1的无符号数是一个很大的正整数,所以大于0。(-1的原码为10000000 00000000 00000000 00000001,补码为11111111 11111111 11111111 11111111,把它转换为无符号后,他的原码、反码和补码就都是一样的了,所以此时的真实值为2^32-1,是个很大的正整数)
数据储存
整形在计算机内存里是以补码形式存储的。
重点是浮点型数据的储存
我们首先了解一下浮点型数据转换成二进制的方法:乘2取整法
将数据的整数部分直接转化为二进制,小数部分则乘以2,如果得到的是个整数,则取1,不是整数则取0,然后再乘以2,直到得到整数为止。
例如:
0.5转化为二进制:
将其小数部分×2,即0.5×2=1为整数,所以取1。所以0.5的二进制为0.1
0.25转化为二进制:
小数部分×2,即0.25×2=0.5不是整数,则取0,然后再用0.5×2得1为整数,则取1,所以0.25的二进制为0.01
又例如5.25转换为二进制
整数部分直接转换为二进制5→101,小数部分0.25→0.01,所以5.25→101.001
了解浮点数转换的方法后我们还需了解一个概念:
在(IEEE)754标准中规定浮点数表示分为3个部分:1、符号位(S,占1bit)2、阶码位(指数位)(E,32位系统中占8bit)3、尾数(M,占剩下的所有位数)
例如0.25的二进制为0.01可以化为1×2^(-2)(S=0,E=-2,M=1)
又比如上面说的5.25的 二进制为101.01就可以化为1.0101×2²(S=0,E=2,M=1.0101)
在储存时本应该是 0 00000010 10101 000000000000000000
但以上表示并不是正确的,因为指数位没有符号,无法表示负数,所以采用另一种表示方法:在指数位+127
即E=2+127=129,于是储存时的二进制码就变成了0 10000001 10101 000000000000000000
不过以上也不是正确答案,我们会发现5.25转化为二进制→1.0101×2²,0.25转化为二进制→
1.0×2^(-2),所有浮点数转化为二进制时小数点都移动到了1后面,所以计算机为了节约一个bit位的空间,就统一把1去掉,只留下后面的数据,只是用的时候再把1加上就行了。
所以正确表示为:0 10000001 0101 0000000000000000000
以上就是我个人对字节序和数据储存的全部理解啦,如有错误还望雅正