文章目录
1.什么是大小端字节序
在我们的电脑中,系统在会将多个字节的数据存储在一片连续的地址上,而将数据的各个字节从这片空间的高地址位开始存储还是从低地址位开始存储就决定了系统的存储字节序
1.1 小端字节序
在32位的操作系统中,int 类型的变量占4个字节,我们利用这样一个变量来说明什么是大端字节序什么是小端字节序;
定义一个变量并赋于初值
int a = 0x12345678;
对于这个整型数,一共有4个字节,从低位到高位,每个字节以此是:78 ; 56 ; 34 ; 12;
数据将会保存在下面内存中:
一共四个字节的地址,假设从0x1001 ~ 0x1004;
那么,对于小端字节序来说系统是这样存储的:
通过图可以发现,小端字节序的存储规则是:
数据的低位存储在低地址位,数据的高位存储在高地址位,小端字节序称为LSB
1.2 大端字节序
数据的低位存储在高地址位,数据的高位存储在低地址位,大端字节序称为MSB
值得补充的是,在网络编程中,计算机的IP地址,在系统中都是以大端字节序来存储的,我们也叫他
网络字节序,所以在我们传IP的时候需要将小端字节序通过函数转成网络字节序;
2.判断电脑是 LSB or MSB
2.1 通过联合union判断
联合union是一个能在同一存储空间中(但不同时)存储不同类型的数据类型
如图:
说白了,就是这段地址空间是大家共用的,具体用到多少空间取决于自身的大小,所以,一个联合体的大小由联合体成员中最大的那个决定;定义一个联合:
union u_data
{
unsinged char a;
unsinged int b;
}data;
如图:
在这个联合体中,他们共用的是低地址位的一个字节,如果我要取b的值,那系统就会根据其对应的大小端字节序来取4个字节的值,而当取a的值时,系统只会从低地址取一个字节;通过这样,我们就可以判断系统是什么字节序了;
我们通过给b赋值,再获取a的值,即可知道系统是LSB还是MSB了;
2.1.1 联合判断是LSB图解
我们按照前面的知识,先假设系统是小端字节序,为b赋值
b = 0x12345678;
系统将会这样存储:
这时,我们要做的,就是打印a的值,如果是小端字节序的这种存储方式,那么,a = 0x78;
2.1.2 联合判断是MSB图解
假设系统是大端字节序:
b = 0x12345678;
如图:
如果系统按照大端字节序这样存储,则a = 0x12;
2.1.3 代码验证
#include <stdio.h>
int main()
{
union u_data
{
unsigned char a;
unsigned int b;
}data;
data.b = 0x12345678;
if( data.a == 0x78 )
{
printf("小端字节序\n");
}
else if( data.a == 0x12 )
{
printf("大端字节序\n");
}
data.a = 0xef; //改变a的值再查看b的值;
printf("%x\n",data.b);
return 0;
}
编译运行代码:
显然,a = 0x78,我们也可以改变a的值,在打印b的值,发现的确,小端字节序是将数据的低位存储在低地址位的;
2.2 通过指针判断
2.2.1 代码演示
#include <stdio.h>
int main()
{
int a = 0x12345678;
char *p = NULL;
p = (char *)&a;
if(*p == 0x78)
{
printf("小端字节序\n");
}
else if(*p == 0x12)
{
printf("大端字节序\n");
}
printf("%x\n",*p);
return 0;
}
指针将会指向整型数的首地址,而当我们调用 *p 往地址里取值时,系统会根据指针的类型的大小取对应大小的值;
例如,char类型的指针就会从他指向的地址往后取char类型(1个字节)大小的值;
所以,当我们使用char类型的指针指向一个int类型的数,再通过 *p 取值时,只会去取其低地址位的1个字节的内容;
如果结果是 *p = 0x78,说明在地址中,低地址位存储了该数据的低位,对应上面的图解,我们就可以判断系统是小端字节序;如果 *p = 0x12,则说明低地址位存储了数据的高位,可判断系统是大端字节序:
2.2.2 编译运行
这就是判断大小端字节序的两种方法了,我的电脑是小端字节序,你的呢?