1.大小端模式的概念
大端模式(big endian
)和小端模式(little endian
)最早是小说格列佛游记中出现的词和计算机本来没关系的。
后来计算机通信发展起来后,遇到一个问题就是:在串口等串行通信中,一次只能发送1个字节。这时候如果要发送一个int
类型的数就会遇到一个问题:int
类型的4个字节是按照:byte0、byte1、 byte2、 byte3这样的顺序发送,还是按照byte3 、byte2 、byte1、 byte0这样的顺序发送,规则就是发送方和接收方必须按照同样的字节顺序来通信,否则就会出现错误。这就叫通信系统中的大小端模式,这是大小端这个词和计算机挂钩的最早问题。
现在我们讲的大小端模式更多是指计算机存储系统的大小端。在计算机内存/硬盘/Nnad中。因为存储系统是32或者64位的,但是数据仍然是按照字节为单位的。以32位机器为例,一个32位的二进制在内存中存储时有2种分布方式:
- 高字节对应高地址,即大端模式。
- 高字节对应低地址,即小端模式。
大端模式和小端模式本身没有对错,没有优劣,理论上按照大端或小端都可以,但是要求必须存储时和读取时按照同样的大小端模式来进行,否则会出错。现实的情况就是:有些CPU公司用大端,比如C51单片机;有些CPU用小端,比如ARM。大部分是用小端模式,大端模式的不算多。于是当我们写代码时,当不知道当前环境是用大端模式还是小端模式时就需要用代码来检测当前系统的大小端。
2.用代码测试当前机器的大小端模式
- 经典C语言笔试题:用C语言写一个函数来测试当前机器的大小端模式。
解决这个问题有2种方式:指针方式或者共用体方式。
2.1共用体方式
#include<stdio.h>
union my_union{ //定义一个共同体
int a;
char b;
};
int is_little_endian(void)
{
//返回1则表示小端模式
union my_union mu;
mu.a = 1;
return mu.b;
}
int main(int argc,char**argv)
{
int a = is_little_endian();
if(a==1)
printf("little.\n");
else
printf("big.\n");
return 0;
}
代码分析:
int
是4字节,char
是1字节,所以自定义共用体的大小就是4字节,mu.a = 1;
将这片内存写成了1。- 1其实就是 00 00 00 01,如果是大端模式,则地址从高到低存放的依次是00 00 00 01;如果是小端模式,则地址从高到低存放的依次是01 00 00 00。
- 这个时候来访问,不管是访问a还是访问b,都是从低地址开始访问的,所以访问
b
,由于b
只占一个字节,所以得到的就是共用体所占空间低地址的第一个字节,大端模式得到的是00,小端模式得到的就是01。
2.2 指针方式
#include<stdio.h>
union my_union{ //定义一个共同体
int a;
char b;
};
int is_little_endian(void)
{
int a=1;
char b =*((char*)(&a));
return b;
}
int main(int argc,char**argv)
{
int a = is_little_endian();
if(a==1)
printf("little.\n");
else
printf("big.\n");
return 0;
}
原理同共用体方法,都是提取一个int
类型1的低字节数据,看是0还是1。