【发布时间】:2019-07-20 03:03:41
【问题描述】:
考虑以下结构
struct a{
uint16_t foo1
uint16_t foo2
uint32_t foo3
uint64_t foo4
uint16_t foo5
uint16_t foo6
}__attribute__(packed);
它有 20 个字节长。没关系,因为结构中的所有内容都与单词边界对齐。
但是,如果善意的开发人员执行以下操作会发生什么:
static struct a foo;
static uint64_t b;
理论上,这会使 b 跨单词边界错位。
有趣的是,gcc 似乎将 foo 对齐到 16 个字节,但是(如果我对汇编的了解是正确的),它允许 b 未对齐:
.local foo.2476
.comm foo.2476,20,16
.local b.2477
.comm b.2477,8,8
我在这里遗漏了什么,或者这是结构打包危险的一个例子?
【问题讨论】:
-
结构体的起始地址总是对齐的,与打包无关。或者至少大多数编译器都是这样的。
-
我知道在数组中,
struct a foo[2]不会对齐。那么struct a foo1; struct a foo2;呢,您是否建议编译器无论如何都会添加填充? -
数组是另一回事。普通的结构数组将在每个对象的末尾添加填充。 C 标准规定数组对象必须相邻分配。因此,如果您删除尾随填充,编译器别无选择,只能分配未对齐的下一个结构项。
-
谁说
b从 4 字节边界开始是错位的?对齐要求是特定于体系结构的,多字节类型的对齐要求可以小于该类型的大小。 -
除非你把它放到另一个打包结构中,否则什么应该阻止编译器在变量之间添加所需的填充?