【发布时间】:2020-10-23 13:18:12
【问题描述】:
在其Common Type Attributes 中,GCC 提供了packed:
此属性,附加到
struct[...] 类型 定义,指定它的每个成员(除了零宽度 位域)被放置以最小化所需的内存。这是 相当于在每个成员上指定packed属性。
此外,来自 C18 标准(第 6.7.2.1、15-17 节):
在结构对象中,非位域成员 [...] 的地址按顺序递增 他们被宣布。指向结构对象的指针,适当地 转换后,指向其初始成员 [...],反之亦然。 结构对象内可能有未命名的填充,但不是 开始。 [...] 结构末尾可能有未命名的填充 [...]。
因此,鉴于结构的开头没有填充,在其第一个成员上使用packed 似乎是多余的。反过来(这就是我的问题所在),在其所有成员上使用packed除了第一个似乎不必要地复杂,相当于在结构本身上使用packed(我们使假设所有成员都是整数类型)。
但是,我曾多次遇到类似以下的代码:
struct S {
unsigned a;
unsigned b __attribute__ ((__packed__));
unsigned c __attribute__ ((__packed__));
unsigned d __attribute__ ((__packed__));
};
我无法弄清楚为什么作者更喜欢这样的斗争
struct S {
unsigned a;
unsigned b;
unsigned c;
unsigned d;
} __attribute__ ((__packed__));
第一个成员上的packed 会改变结构本身的对齐问题吗?它是否来自我没有考虑过的填充和对齐以外的其他东西(例如旧版本的 GCC 中的怪癖)?另一方面,如果它们是等价的,我怎么能确定它,因为这里的文档是恕我直言,帮助不大?
虽然不能有效证明它们是等价的,但我尝试为各种架构(x86、x86_64、Aarch64)编译structs,它们似乎总是共享相同的布局。
【问题讨论】:
-
第一个成员保证位于偏移量零处。
-
gcc 非标准扩展就像标准 C 一样——它们带有许多无用的特性。没有充分的理由说明您只想打包结构的某些成员。为什么有些人坚持使用无用的功能是心理问题,而不是编程问题。
-
顺便说一句,如果您想对此进行试验,请使用一些较小的类型,例如
short。上述架构可以读取 32 位对齐的数据,因此没有理由需要填充。 -
所有成员真的都是同一种类型吗?
-
@IanAbbott 是的;有什么重要的原因吗?
标签: c struct memory-alignment packed gcc-attribute