在开发ethercat协议栈邮箱通讯的过程中遇到一个BUG,主站协议栈传过来的邮箱数据包是正确的,但是到FOE服务处理时,使用结构体引用的方式处理时发现数据是不对的。
如下所示
1 UINT8 MailboxServiceInd(TMBX MBXMEM *pMbx) 2 { 3 UINT8 result; 4 5 /*only FoE is allowed in Boot mode*/ 6 if(bBootMode == TRUE && (MBX_TYPE_FOE != ((pMbx->MbxHeader.Flags[MBX_OFFS_TYPE] & MBX_MASK_TYPE) >> MBX_SHIFT_TYPE ))) 7 return MBXERR_UNSUPPORTEDPROTOCOL; 8 switch ( (pMbx->MbxHeader.Flags[MBX_OFFS_TYPE] & MBX_MASK_TYPE) >> MBX_SHIFT_TYPE ) 9 { 10 case MBX_TYPE_COE: 11 /* CoE datagram received */ 12 result = COE_ServiceInd((TCOEMBX MBXMEM *) pMbx); 13 break; 14 case MBX_TYPE_FOE: 15 /* FoE datagram received */ 16 result = FOE_ServiceInd((TFOEMBX MBXMEM *) pMbx); 17 18 default: 19 20 result = MBXERR_UNSUPPORTEDPROTOCOL; 21 break; 22 } 23 24 return result; 25 }
在第1行传入了一个结构体类型为TMBX 的*pMbx,在第16行将其强制转换成了 TFOEMBX类型的结构体。
两个结构体定义如下:
TMBX
1 typedef struct MBX_STRUCT_PACKED_START 2 { 3 TMBXHEADER MbxHeader; /**< \brief Mailbox header*/ 4 UINT16 Data[(MAX_MBX_DATA_SIZE >> 1)]; /**< \brief Mailbox data*/ 5 }MBX_STRUCT_PACKED_END 6 TMBX;
1 typedef struct MBX_STRUCT_PACKED_START 2 { 3 TMBXHEADER MbxHeader; /**< \brief Mailbox header*/ 4 TFOEHEADER FoeHeader; /**< \brief FoE header*/ 5 UINT16 Data[((MAX_MBX_DATA_SIZE)-(FOE_HEADER_SIZE)) >> 1]; /**< \brief FoE Data buffer*/ 6 }MBX_STRUCT_PACKED_END 7 TFOEMBX;
1 typedef struct MBX_STRUCT_PACKED_START 2 { 3 UINT16 OpCode; /**< \brief OpCode 4 * 5 * 1 : RRQ<br> 6 * 2 : WRQ<br> 7 * 3 : DATA<br> 8 * 4 : ACK<br> 9 * 5 : ERR<br> 10 * 6 : BUSY*/ 11 union MBX_STRUCT_PACKED_START 12 { 13 UINT32 Password; /**< \brief Password (used in Read request and Write request). 0 if unknown*/ 14 UINT32 PacketNo; /**< \brief Packet number (used in DATA and ACK datagram)*/ 15 UINT32 ErrorCode; /**< \brief Error code (used in ERR datagram)*/ 16 struct MBX_STRUCT_PACKED_START 17 { 18 UINT16 Done; /**< \brief Done indication (used in BUSY datagram)*/ 19 UINT16 Entire; /**< \brief Entire indication (used in BUSY datagram)*/ 20 }MBX_STRUCT_PACKED_END 21 Busy; /**< \brief Busy variable*/ 22 }MBX_STRUCT_PACKED_END 23 Cmd; /**< \brief Command field*/ 24 }MBX_STRUCT_PACKED_END 25 TFOEHEADER;
1 typedef struct MBX_STRUCT_PACKED_START 2 { 3 UINT16 Length; /**< \brief Length*/ 4 UINT16 Address; /**< \brief Address*/ 5 6 UINT16 Flags[1]; /**< \brief Flags*/ 7 #define MBX_OFFS_TYPE 0 /**< \brief Protocol type offset*/ 8 #define MBX_MASK_TYPE 0x0F00 /**< \brief Protocol type mask*/ 9 #define MBX_SHIFT_TYPE 8 /**< \brief Protocol type shift*/ 10 #define MBX_OFFS_COUNTER 0 /**< \brief Protocol counter offset*/ 11 #define MBX_MASK_COUNTER 0xF000 /**< \brief Protocol counter mask*/ 12 #define MBX_SHIFT_COUNTER 12 /**< \brief Protocol counter shift*/ 13 }MBX_STRUCT_PACKED_END 14 TMBXHEADER;
可以看到出问题的是在TFOEHEADER结构体中,联合体为4个字节,编译时系统会把该头文件按照4字节对齐,从而实际占用8个字节而不是6个字节,使用sizeof()验证也确实如此,当把函数传入的结构体*pMbx强制转换成TFOEMBX结构体就会出现问题。
解决方式使用#pragma pack(2) 强制编译器按照2字节对齐
将TFOEHEADER结构体强制为2字节对齐,代码如下:
1 #pragma pack(2) //此结构体在强制邮箱结构体类型转换时内存对齐发生错误 2 typedef struct MBX_STRUCT_PACKED_START 3 { 4 UINT16 OpCode; /**< \brief OpCode 5 * 6 * 1 : RRQ<br> 7 * 2 : WRQ<br> 8 * 3 : DATA<br> 9 * 4 : ACK<br> 10 * 5 : ERR<br> 11 * 6 : BUSY*/ 12 union MBX_STRUCT_PACKED_START 13 { 14 UINT32 Password; /**< \brief Password (used in Read request and Write request). 0 if unknown*/ 15 UINT32 PacketNo; /**< \brief Packet number (used in DATA and ACK datagram)*/ 16 UINT32 ErrorCode; /**< \brief Error code (used in ERR datagram)*/ 17 struct MBX_STRUCT_PACKED_START 18 { 19 UINT16 Done; /**< \brief Done indication (used in BUSY datagram)*/ 20 UINT16 Entire; /**< \brief Entire indication (used in BUSY datagram)*/ 21 }MBX_STRUCT_PACKED_END 22 Busy; /**< \brief Busy variable*/ 23 }MBX_STRUCT_PACKED_END 24 Cmd; /**< \brief Command field*/ 25 }MBX_STRUCT_PACKED_END 26 TFOEHEADER; 27 #pragma pack()
标签:STRUCT,brief,UINT16,MBX,内存,对齐,强制,TYPE,PACKED From: https://www.cnblogs.com/mangorange/p/17430355.html