编译器如何处理错位?

时间:2015-10-21 19:12:18

标签: c gcc padding compiler-optimization

SO问题Does GCC's __attribute__((__packed__))…?提到__attribute__((__packed__))执行"打包,这会在访问打包结构的字段时引入对齐问题。当直接访问字段时,编译器将对此进行说明,而不是通过指针访问它们时#34;

编译器如何确保直接访问字段?我想它在内部添加一些填充或做一些指针魔术。在下面的例子中,编译器如何确保与指针相比正确访问y

struct packet {
    uint8_t x;
    uint32_t y;
} __attribute__((packed));

int main ()
{
    uint8_t bytes[5] = {1, 0, 0, 0, 2};
    struct packet *p = (struct packet *)bytes;

    // compiler handles misalignment because it knows that
    // "struct packet" is packed
    printf("y=%"PRIX32", ", ntohl(p->y));

    // compiler does not handle misalignment - py does not inherit
    // the packed attribute
    uint32_t *py = &p->y;
    printf("*py=%"PRIX32"\n", ntohl(*py));
    return 0;
}

1 个答案:

答案 0 :(得分:2)

当编译器看到符号p->y时,由于p的声明,它知道您正在访问结构成员,并且结构已打包。它将其转换为逐字节读取的代码,并执行必要的位移以将它们组合成uint32_t变量。从本质上讲,它将表达式p->y视为类似于:

*((char*)p+3) << 24 + *((char*)p+2) << 16 + *((char*p)+1) << 8 + *(char*)p

但是当您通过*py进行间接时,编译器并不知道该变量的值来自何处。它不知道它指向一个打包的结构,所以它需要执行这种转换。声明py指向uint32_t,通常可以使用一次读取整个32位字的指令来访问query.exec(function(err, result))。但是这条指令要求指针与4字节边界对齐,所以当你尝试这样做时,你会因为未对准而得到总线错误。