Fork me on GitHub

结构体、数组的联合体对数据包的解包对齐问题

结论:在使用用联合体包装 嵌结构体、和数组,从而对数据数组解包时,结构体的4字节对齐可能会产生解包错误。需要添加1字节对齐指令 __attribute__((packed))

如以下数据包:

//数据
unsigned char data1[] = {
        0x01,0x00,0xFF,0x48,0x45,0x4C,0x4C,0x4F,0x2E,0x74,0x78,0x74,0x00,0x31,0x31,0x20,
        0x31,0x34,0x36,0x33,0x37,0x34,0x36,0x32,0x37,0x37,0x32,0x20,0x30,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x4C,0x1A
};
//数据包共同体
#define PKT_SIZE 128
typedef union
{
  // YModem数据包结构
  struct {
      uint8_t header;             // 数据包头部(SOH或STX)
      uint8_t blockNumber;        // 数据包序号
      uint8_t blockNumberC;       // 数据包序号的补码
      uint8_t data[PKT_SIZE]; // 数据包内容
      uint16_t crc;               // CRC校验
  }UnPack;
  uint8_t buff[PKT_SIZE + 5];
}YModemPacketType;

int main()
{
    YModemPacketType yModemStruct;
    memcpy(yModemStruct.packet.buff,data1,128+5);
    printf("%x",yModemStruct.crc);//输出为 0x001a 或0xnn1a
}

结构体默认会对不同类型的变量经行4字节大小的对齐,头三个变量为uint8_t 是同种变量,在内存上是连续的,第四个变量也是uint8_t,在内存上紧跟前面,但是,由于uint8_t data[128]是128字节的,后面有紧跟其他类型的变量uint16_t 的UnPack.crc,因此,在UnPack.data[127] 的后面,UnPack.crc 的前面的一个字节内存上,会产生空内存。因此访问UnPack.crc时, 会出现0xNN1A NN的值不可控。

解决方法:在声明的结构体前面使用__attribute__((packed)) 的按字节对齐命令,

其他命令:__attribute__((aligned(4))) 按四字节对齐。

typedef union
{
  // YModem数据包结构
  struct __attribute__((packed)){
      uint8_t header;             // 数据包头部(SOH或STX)
      uint8_t blockNumber;        // 数据包序号
      uint8_t blockNumberC;       // 数据包序号的补码
      uint8_t data[PKT_SIZE]; // 数据包内容
      uint16_t crc;               // CRC校验
  };
  uint8_t buff[PKT_SIZE + 5];
}YModemPacketType;
int main()
{
  YModemPacketType yModemStruct;
  memcpy(yModemStruct.buff, data1, sizeof(data1));
  printf("%x",yModemStruct.crc);//输出为 1a4c 电脑和STM32是小端模式,数据低位在地址低位
  return 0; 
}
posted @ 2024-07-25 12:13  赤诚Xie  阅读(0)  评论(0编辑  收藏  举报