【问题标题】:How does the compiler handle the misalignment?编译器如何处理错位?
【发布时间】:2015-10-21 19:12:18
【问题描述】:

SO 问题Does GCC's __attribute__((__packed__))…? 提到__attribute__((__packed__)) 确实“打包会在访问打包结构的字段时引入对齐问题。编译器将在直接访问字段时考虑这一点,但在访问字段时不会考虑通过指针”。

编译器如何确保直接访问字段?我想它在内部添加了一些填充或做一些指针魔术。在下面的例子中,编译器如何确保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;
}

【问题讨论】:

  • 我不认为你可以通过在@ 符号中提及某人的名字来邀请某人回答你的问题;他们必须已经发表评论(对此问题),然后您的评论就是对他们的回复。因此,如果 Ambroz 没有因为您的评论而注意到这个问题,您应该不会感到惊讶。
  • 您不能使用 at 符号语法来 ping 某人,除非他们已经参与了您发布的线程。在这里向特定用户提出问题也不合适。这不是聊天室或“做我的私人顾问或老师”网站。
  • 这是目标极其重要的目标之一。例如,对齐在 z80 上甚至不是真正的事情,在 x86 上大多是可选的,但在某些 RISC 架构上至关重要。那么,你想针对什么目标考虑这个问题呢?
  • @harold:基本上我在使用 arm 的嵌入式环境中工作。无论如何,这个问题得到了 Barmer 的出色回答。
  • 对于 ARM,它取决于版本。

标签: c gcc padding compiler-optimization


【解决方案1】:

当编译器看到符号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 位字的指令来访问它。但这条指令要求指针与 4 字节边界对齐,因此当您尝试这样做时,由于未对齐,您会收到总线错误。

【讨论】:

  • @Barmer:哦,这就是为什么我记得某个时候回到某个地方,与对齐访问相比,未对齐的内存访问导致比对齐的内存访问更多的读取,因为编译器发出更多用于读取内存的指令。因此,在未对齐整数访问的情况下,编译器发出 4 条指令来获取整数内存,而在对齐内存的情况下只有一次访问,对吗?
  • 是这样吗?像这样的未对齐读取只是 x86 上的一条指令,除非编译器很傻。
  • 取决于具体的硬件架构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-29
  • 1970-01-01
相关资源
最近更新 更多