将二进制数据读入内存结构,效果奇怪

Gun*_*ars 2 c data-structures

我已经在这一段时间了,这真的让我很困惑.这是一个非常精简的代码片段,可以重现这个问题:

uint8_t dataz[] = { 1, 2, 3, 4, 5, 6 };

struct mystruct {

    uint8_t dummy1[1];
    uint16_t very_important_data;
    uint8_t dummy2[3];

} *mystruct = (void *) dataz;

printf("%x\n", mystruct -> very_important_data);
Run Code Online (Sandbox Code Playgroud)

你期望什么应该是输出?我会说x302,但不是.它给了我x403.与使用此结构相同:

struct mystruct {

    uint8_t dummy1[2];
    uint16_t very_important_data;
    uint8_t dummy2[2];

} *mystruct = (void *) dataz;
Run Code Online (Sandbox Code Playgroud)

你会怎么解释?

jim*_*ara 5

填料.不能保证结构的成员在结构中的物理位置.它们可能是字对齐的,留下空白.

在某些版本的C中有pragma来明确控制打包.


Tim*_*fer 5

正如其他人所提到的,除非您的编译器对齐是字节对齐的,否则您的结构可能会有"漏洞".编译器这样做是因为它加速了内存访问.

如果你正在使用gcc,那么有一个"packed"属性会导致struct被字节对齐,所以删除"holes":

struct __attribute((__packed__)) mystruct {
    uint8_t dummy1[1];
    uint16_t very_important_data;
    uint8_t dummy2[3];
} *mystruct = (void *) dataz;
Run Code Online (Sandbox Code Playgroud)

但是,这不一定能解决问题.16位值可能未设置为您认为应该的值,具体取决于计算机的字节顺序.您将不得不在结构中的任何多字节整数中交换字节.没有通用的功能,因为它需要在运行时有关结构布局的信息,而C不提供.

将结构映射到二进制数据通常是不可移植的,即使您现在可以在机器上运行它.

  • 它不仅加快了访问速度 - 在某些平台上,未对齐访问会引发异常,从而终止您的进程. (3认同)