将字节复制到struct会产生错误的值

时间:2014-04-25 01:14:47

标签: c struct memcpy

我正在尝试将字节数组复制到结构中:

实际字节数:

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

目的地结构:

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;

但由于某种原因,myStruct.status中的字节不是它们应该是的字节:

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?

用于复制这些字节的代码:

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

此代码在ARM(iPhone 5)上运行,这可能解释了输出的小端性,但它没有解释为什么在复制的字节中有+4字节的偏移量。

这里发生了什么?

2 个答案:

答案 0 :(得分:2)

结构的内存布局将符合其成员的对齐要求。在32位ARM上,16位值需要2字节对齐,32位和更大值需要4字节对齐。当对齐方式彼此不匹配时,结构元素之间存在填充字节。由于这种填充,将字节数组复制或转换为结构不会像预期的那样工作。

不幸的是,没有什么好办法解决这个问题。您可以选择打包您的结构,这可能会降低其性能。您可以单独复制每个元素。或者您可以仔细安排您的结构,以便它们紧密包装(假设您了解代码将运行的所有平台的对齐规则)。

例如:如果你以这种方式重新排列结构,它将完美地填充中间或末尾没有填充字节(它是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;

答案 1 :(得分:0)

编译器对齐struct中的元素,以便所有这些元素占用内存中等于4的倍数的空间。

所以基本上,command,据说只使用1个字节,然后是status之前的3个字节的垃圾。

您可以通过设置:

告诉编译器不要这样做
#pragma pack(1)