Search code examples
cmemory-managementstructpaddingunions

C union containing structs - memory mapping - compiler skips one byte?


Somewhat confusing title, i know.

I created a union that contains a "raw"-array and 2 structs. These 2 structs each contain a struct header_t, a union of structs and a uint8_t. i have attached only the inMsg_t since both structs are made up the same way.

typedef struct sAfRegisterSRSP{
    uint8_t Status;
} tAfRegisterSRSP;

typedef union InOutMsg_u{
    uint8_t raw[ZIGBEE_PAYLOAD_MAX];
    outMsg_t outMsg;
    inMsg_t inMsg;
}msg_t;   


typedef struct header_s{
    uint8_t len;    ///< packet len 
    uint8_t cmd0;   ///< type (Bit: 7-5) and subsystem (Bit 4-0))
    uint8_t cmd1;   ///< command identifier
}header_t;


typedef struct inMsg_s{
    header_t header;
    union payload_u{
        tAfRegisterSRSP               afRegisterSRSP;
        tAfDataRequestSRSP            afDataRequestSRSP;
        tAfIncomingMsgAREQ            afIncomingMsgAREQ;
        tAfDataConfirmAREQ            afDataConfirmAREQ;

        tZbStartRequestSRSP           zbStartRequestSRSP;
        tZbPermitJoiningRequestSRSP   zbPermitJoiningRequestSRSP;
    } payload;
    uint8_t checksum;   //just a placeholder; cannot be used practically
}inMsg_t;

Now, when i run the code the memory mapping of the header-bytes is fine. byte[0] of the raw array maps to the len-field in the header-struct. cmd0 and cmd1 as well. However, "status" from the afRegisterSRSP-struct does not point to the status-byte, but to the CRC-Byte, that's after the status byte. This is also clear when looking at the memory addresses.

The header fields are at address: 0x15F6, 0x15F7 and 0x15F8.

Then the first payload-byte is at 0x15FA and 0x15F9 is left out.

I have attached a screenshot of the memory as it is shown in the debugger.

I can't figure out why the one byte is skipped and how to fix it.


Solution

  • The payload union is being aligned to a four byte boundary, and the header is only three bytes long. That means there is a pad byte in the C definition of the structure, but your memory mapping likely is packed, omitting all padding. You'd need to use a compiler specific flag, pragma, or attribute to specify that the various unions/structures are packed (to one byte alignment) to ensure no padding bytes are created. For example, gcc packing and Visual Studio packing.

    Also, depending on your disk data format, you may need to be careful to perform byte swapping to switch from machine native endianness (often little endian, e.g. on x86) to network endianness (usually big endian, with exceptions for a few Windows specific protocols).