程序数据存储中的大端小端问题
程序数据存储中的大端小端问题
事情是这样的,有一次我使用TPC116S8 DAC芯片,该芯片是使用SPI方式进行数据传输,通讯协议如下图所示:
可以看出来,一次传输需要传输24个bit,而且是高位在前(MSB)。
所以我就想着将数据存放到一个32位的存储空间里,然后取其低3个Byte进行传输即可。然后发现通讯不正常,通过示波器测量波形发现,数据位并没有按照预想的那样进行传输。突然想到有可能是数据大小端存储方式的问题。
MSB:Most Significant Bit,最高有效位。
LSB:Last Significant Bit,最低有效位。
大端和小端
大端模式(Big-Endian):数据的低位Byte存放在高位地址中,高位Byte存放在低位地址中。
小端模式(Little-Endian):数据的低位Byte存放在低位地址中,高位Byte存放在高位地址中。
举个例子:
对于一个无符号32位整数0x12345678
来说,大端、小端的存储模式分别如下图所示:
这就回到了最开始的那个问题,我想传输0x12345678
的低3个Byte(低24bit)0x345678
:
uint32_t mdata = 0x12345678;
SPI_Transmit((uint8_t *)&mdata+1, 3);//传输指定地址开始的三个字节
如果是小端存储模式,则传输的数据为0x56、0x34、0x12
。
如果是大端存储模式,则传输的数据为0x34、0x56、0x78
。
可以看出来,如果是大端存储,传输的数据则是我想要的。
判断计算机是大端存储还是小端存储
将以下C程序自己的电脑上运行一下:
#include <stdio.h>
#include <stdint.h>
//联合体
union mdata{
uint32_t a;
uint8_t b[4];
}tmp;
int main()
{
tmp.a = 0x12345678;
printf("b1:%x, b2:%x, b3:%x, b4:%x\n",tmp.b[0],tmp.b[1],tmp.b[2],tmp.b[3]);
return 0;
}
小端模式的运行结果为:b1:78, b2:56, b3:34, b4:12
。
大端模式的运行结果为:b1:12, b2:34, b3:56, b4:78
。
一般来说,Windows系统为小端存储,Linux系统为大端存储。
将其封装成一个函数,用来判断是大端还是小端。
int IsLittleEndian()
{
int a = 0x1234;
char b = *(char *)&a; //通过将int强制类型转换成char单字节,通过判断起始存储位置。即等于取b等于a的低地址部分
if( b == 0x34)
{
return 1;//little endian
}
return 0;//big endian
}
大端小端转换
定义2个函数EndianSwap16()
、EndianSwap32()
,分别为16位和32位的字节序转换函数。
//16位大小端转换函数
#define EndianSwap16(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
(((uint16_t)(A) & 0x00ff) << 8))
//32位大小端转换函数
#define EndianSwap32(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
(((uint32_t)(A) & 0x00ff0000) >> 8) | \
(((uint32_t)(A) & 0x0000ff00) << 8) | \
(((uint32_t)(A) & 0x000000ff) << 24))