字节序(大端/小端)
字节序与大小端
- 字节是计算机内部的基本存储单元,一个数据通常由多个字节(Byte)构成。如int类型的变量,在32位系统中则由4个Byte组成,字节序则指存放在计算机内部的这4个Byte的存储顺序,顺序有两种:
如有int a = 0x12345678
(最低位(Most Least Bit)为16进制的8,是最低有效位;最低位(Most Significant)为16进制的1,是最高有效位)
- 低地址存储低地址字节,高地址存储高地址字节 -> 小端
- 低地址存储高地址字节,高地址存储低地址字节 -> 大端
如图1:
如图2:
平台与大小端
- 不同架构的处理器,存储模式一般也不同。ARM、X86、DSP一般都采用小端模式,而IBM、Sun、PowerPC架构的处理器一般都采用大端模式
查看运行平台的大小端
#include <stdio.h>
int main()
{
int a = 0x12345678;
char b = a;
// int类型变量占4个字节
// char类型变量占4个字节
// 当字节占用数较多的类型(如:int)给字节字节占用数较少的类型(如:char)赋值时,会发生“截断”
// 即低字节的数据保留,高字节的数据被舍弃,所以可以利用这个原理查看变量a的字节序为大端还是小端
if(b == 0x78)
{
printf("Little endian!\n");
}
else{
printf("Big endian!\n");
}
return 0;
}
为什么不同架构的处理器在存储模式上会有大小端之分呢?
- 小端模式低地址存储低字节数据,比较符合人类的思维习惯;
- 而大端模式则更适合计算机的处理习惯:不需要考虑地址和数据的对应关系,以字节为单位,把数据从左到右,按照由低到高的地址顺序直接读写即可。大端模式一般用在网络字节序、各种编解码中。作为一名嵌入式工程师,掌握大端模式与小端模式的存储方式很有必要。我们在驱动开发中配置各种寄存器,经常需要对某个寄存器的几个比特位进行读写操作。不同存储模式的嵌入式设备互联及网络数据传输,也需要考虑大小端模式,在处理网络数据时需要自己实现数据的大小端转换。如果你写的程序代码要在不同架构的嵌入式平台上运行(如ARM、PowerPC),还是要考虑大小端模式的转换的。
大小端的转换
在一个嵌入式系统软件中,如何实现大小端存储模式的转换呢?我们可以定义一个宏,将高、低地址上的数据互换,即可完成大小端存储模式的转换。
在Linux内核源码的头文件目录include/linux/byteorder下,有3个头文件big_endian.h、generic.h、little_endian.h。在这3个头文件中定义了各种宏,实现了不同类型数据的大小端存储模式的相互转换,大家在驱动开发或内核编程中可以直接使用这些封装好的API,不需要自己再重复定义了
Reference: