结构体必须字节对齐的一种情况

2023-12-27  本文已影响0人  xEndLess

MCU:STM32F407
RTOS: FreeRTOS

1. 情况说明

定义了两个结构体全局变量power_down_infocoordinate_ee。这两个全局变量会被保存到AT24C64中。power_down_infocoordinate_ee的定义如下:

typedef struct {
    uint16_t valid_flag;
    uint32_t storage[1][2];
    uint32_t get[1][2];
    uint32_t rfid1[1][2];
    uint32_t rfid2[1][2];
} coordinate_ee_t;

// typedef enum { NO_CARD, HAVE_CARD } feed_card_box_status_e;
typedef struct {
    uint16_t card_amount[FEED_CARD_BOX_NUM]; /* 投卡仓卡片数量 */
    int8_t   sequence[FEED_CARD_BOX_NUM];    /* 喂卡顺序,负数的话不考虑顺序 */
    int8_t   current_card_box_num;           /* 当前走卡的投卡仓编号,根据该值,确认是否 */
} feed_card_info_t;

typedef struct {
    uint8_t rfid[STORAGE_CARD_BOX_NUM][RFID_BYTE_LEN]; /* RFID编号 */
    int16_t card_amount[STORAGE_CARD_BOX_NUM];         /* 卡片数量 */
    uint8_t cur_box_num;                               /* 当前卡箱号, 0 - 5 */
} storage_card_info_t;

/* 掉电保存数据结构体 */
typedef struct power_down_info {
    uint16_t            init_flag;
    int8_t              current_feed_card_box_num; /* 0-3正常卡仓号,其他异常 */
    feed_card_info_t    feed_card_info;            /* 投卡口信息 */
    int8_t              slot_card_amount;          /* 衔接槽中卡片数量 */
    storage_card_info_t storage_card_info;         /* 存卡箱内卡片数量 */
} power_down_info_t;

extern power_down_info_t power_down_info;
extern coordinate_ee_t   coordinate_ee;

查看MAP文件中可以power_down_infocoordinate_ee的地址是连续的。

 .bss.coordinate_ee
                0x200001bc       0x22 build/main.o
                0x200001bc                coordinate_ee
 *fill*         0x200001de        0x2 
 .bss.power_down_info
                0x200001e0       0x36 build/main.o
                0x200001e0                power_down_info
 *fill*         0x20000216        0x2 

2. 问题

当从AT24C64中读出coordinate_ee时,在读取coordinate_ee的最后一个字节时,会导致power_down_info的第一个字节变化。power_down_info.init_flag的值从0x5A5A 变为0x5AFF。

EEPROM_IIC_ReadBuffer(EEPROM_COORDINATE_ADDRESS, (uint8_t *)&coordinate_ee, sizeof(coordinate_ee));

3. 分析

产生上述问题的原因是sizeof(coordinate_ee)是按照4字节对齐计算长度的。从AT24C64中读出coordinate_ee时,如果coordinate_ee的实际长度不是4的倍数,会占用power_down_info的头部地址空间。导致power_down_info的成员变量的值变化。

4. 结论

在执行AT24C64的读写操作时,涉及的变量必须按字节对齐。gcc下按字节对齐的方法时增加#pragma pack(1)和#pragma pack()。如下所示:

#pragma pack(1)
typedef struct {
    uint16_t valid_flag;
    uint32_t storage[1][2];
    uint32_t get[1][2];
    uint32_t rfid1[1][2];
    uint32_t rfid2[1][2];
} coordinate_ee_t;

// typedef enum { NO_CARD, HAVE_CARD } feed_card_box_status_e;
typedef struct {
    uint16_t card_amount[FEED_CARD_BOX_NUM]; /* 投卡仓卡片数量 */
    int8_t   sequence[FEED_CARD_BOX_NUM];    /* 喂卡顺序,负数的话不考虑顺序 */
    int8_t   current_card_box_num;           /* 当前走卡的投卡仓编号,根据该值,确认是否 */
} feed_card_info_t;

typedef struct {
    uint8_t rfid[STORAGE_CARD_BOX_NUM][RFID_BYTE_LEN]; /* RFID编号 */
    int16_t card_amount[STORAGE_CARD_BOX_NUM];         /* 卡片数量 */
    uint8_t cur_box_num;                               /* 当前卡箱号, 0 - 5 */
} storage_card_info_t;

/* 掉电保存数据结构体 */
typedef struct power_down_info {
    uint16_t            init_flag;
    int8_t              current_feed_card_box_num; /* 0-3正常卡仓号,其他异常 */
    feed_card_info_t    feed_card_info;            /* 投卡口信息 */
    int8_t              slot_card_amount;          /* 衔接槽中卡片数量 */
    storage_card_info_t storage_card_info;         /* 存卡箱内卡片数量 */
} power_down_info_t;
#pragma pack()
上一篇下一篇

猜你喜欢

热点阅读