大小端和字节对齐
问题背景
在嵌入式开发中,我们经常需要处理各种网络协议,比如我们自定义一套下位机(Sensor)和上位机的通信协议,它们可能通过以太网、串口(UART)、SPI、I2C 等总线进行传输,实现多端通信。

在 C/C++ 编程中,通常会使用 struct 结构体或者 class 类来定义协议格式。举个例子,假设我们的协议需要传输 Sensor 采集的数据到上位机进行显示,那么我们会将数据塞到 Packet 数据包中,为了增加数据包的可解释性和安全性,我们通常还会为其增加数据包头(Header)和包尾(Tail)。现在,假设我们制定了如下协议:
| 区域 | 字段 | 字节 |
|---|---|---|
| Header | Distance | 2 字节 |
| Azimuth | 2 字节 | |
| Elevation | 2 字节 | |
| Intensity | 1 字节 | |
| Reserved | 2 字节 | |
| Block | Unit1 | 9 字节 |
| Unit2 | 9 字节 | |
| ...... | ...... | |
| Unit32 | 9 字节 | |
| Tail | CRC | 4 字节 |
| FunctionSafety | 17 字节 |
其中包头(Header)部分一共 9 个字节;包体(Block)一共包含 32 个 Unit 单元,每个单元占用 9 个字节,共计 288 字节;包尾(Tail)包含 CRC 校验码和功能安全(FunctionSafety)信息,共计 21 字节。因此,整个 Packet 的大小是 9 + 288 + 21 = 318 字节。
如果用结构体来定义,类似于下面这样:
typedef struct
{
uint16_t sob;
uint16_t pkgLen;
uint32_t frameID;
uint8_t version;
} DemoHeader;
typedef struct
{
uint16_t distance;
uint16_t azimuth;
uint16_t elevation;
uint8_t intensity;
uint16_t reserved;
} DemoUnit;
typedef struct
{
DemoUnit units[32];
} DemoBlock;
typedef struct
{
uint32_t crc;
uint8_t functionSafety[17];
} DemoTail;
typedef struct
{
DemoHeader header;
DemoBlock block;
DemoTail tail;
} DemoPacket;
看起来很棒,现在我们来计算一下包的大小,添加如下代码:
#include <stdio.h>
#include <stdint.h>
/* 结构体定义,忽略 */
int main(void)
{
DemoPacket packet;
printf("Size of DemoPacket = %lu\n", sizeof(packet));
printf("Size of DemoPacket.Header = %lu\n", sizeof(packet.header));
printf("Size of DemoPacket.Block = %lu\n", sizeof(packet.block));
printf("Size of DemoPacket.Tail = %lu\n", sizeof(packet.tail));
return 0;
}
运行程序,输出结果如下:
Size of DemoPacket = 356
Size of DemoPacket.Header = 12
Size of DemoPacket.Block = 320
Size of DemoPacket.Tail = 24
咦。。。怎么跟协议里规定的 318 个字节对不上?