Question

I'm trying to copy a byte array to a struct:

Actual bytes:

00000000 | ff 53 4d 42 72 00 00 00 00 08 01 c8 00 00 00 00 | .SMBr...........

Destination structure:

typedef struct {
    uint8_t protocol[4];
    uint8_t command;
    uint32_t status;
    uint8_t flags;
    uint16_t flags2;
    uint16_t pidHigh;
    uint16_t somethingElse;
} MyStruct;

But for some reason, bytes in myStruct.status are not what they're supposed to be:

printf("%x", bytes[4]);
  => 72          // Ok

printf("%x", myStruct.command);
  => 72          // Ok

printf("%02x%02x%02x%02x", bytes[5], bytes[6], bytes[7], bytes[8]);
  => 00000000    // Ok

printf("%"PRIX32, myStruct.status);
  => C8010800    // What?! Why did it take the next 4 bytes... and reversed them?

Code used to copy those bytes:

MyStruct myStruct; 
memcpy(&myStruct, bytes, 16);

This code is running on ARM (iPhone 5), which might explain the little-endianness of the output, but it doesn't explain why there's a +4 bytes offset in the bytes that've been copied.

What's going on here?

Was it helpful?

Solution 2

The compiler aligns the elements in the struct, so that all of them occupy a space in memory equal to a multiple of 4.

So basically, command, that supposedly uses 1 byte only, is followed by 3 bytes of garbage before status.

You can tell the compiler to not do that by setting this:

#pragma pack(1)

OTHER TIPS

The memory layout of a struct is going to conform to the alignment requirements of its members. On 32-bit ARM, 16-bit values need 2 byte alignment and 32-bit and greater values require 4 byte alignment. There are padding bytes in between the structure elements when the alignment doesn't match from one to another. Due to this padding, copying or casting arrays of bytes to a struct is not going to work as you expect.

Unfortunately, there is no great way around this. You can choose to pack your structures, which may reduce their performance. You can copy each element individually. Or you can carefully arrange your structures so that they are tightly packed (assuming you are aware of the alignment rules for all platforms your code will run on).

For example: if you rearrange you struct in this way, it will be perfectly packed with no padding bytes in the middle or at the end (it is an even multiple of 4).

typedef struct {
    uint32_t status;           // +0
    uint16_t flags2;           // +4
    uint16_t pidHigh;          // +6
    uint16_t somethingElse;    // +8
    uint8_t command;           // +10
    uint8_t flags;             // +11
    uint8_t protocol[4];       // +12
} MyStruct;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top