【问题标题】:Is a C struct of all-packed fields except first one different from packed struct?除了第一个之外,所有压缩字段的 C 结构与压缩结构不同吗?
【发布时间】: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


【解决方案1】:

如果第一个成员没有打包,它仍然有它原来的对齐要求,可能大于一个字节,因此结构至少有对齐要求,这也可能需要在结构的末尾填充.

为:

struct S {
    unsigned a;
    unsigned b __attribute__ ((__packed__));
    unsigned c __attribute__ ((__packed__));
    unsigned d __attribute__ ((__packed__));
};

GCC 10.2 for x86-64 表示 _Alignof(struct S) 为 4。而如果 a 或整个结构标记为 __attribute__ ((__packed__));,则表示对齐为 1。

如果我们把最后一个成员改成char

struct S {
    unsigned a;
    unsigned b __attribute__ ((__packed__));
    unsigned c __attribute__ ((__packed__));
    char d __attribute__ ((__packed__));
};

然后 GCC 说它的大小是 16 字节,表明它添加了三个字节的填充。如果a 或整个结构标记为__attribute__ ((__packed__)),则大小将更改为13。

【讨论】:

  • 感谢您的回答;有趣(也很讽刺?)看到,在你的第二个例子中,即使dpacked,由于S 的对齐约束,它后面也会有填充,继承自a!所以这意味着“除第一个成员之外的所有成员上的packed”等同于结构上的__attribute__((packed, aligned(_Alignof(T)))),其中T 是其第一个成员的类型?还是有其他区别?
  • 在 gcc 中,如果属性未应用于整个结构,它只是 never 打包结构。即使您适用于所有成员。漏洞?未实施?
  • @P__J__:如果打包应用于每个成员但不应用于结构,则 GCC 会打包结构。 Here 我们看到这样一个结构,它的大小为 11 字节,对齐要求为 1。11 只够成员(4+1+4+2)的字节,没有填充,所以结构被打包了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
  • 2016-08-11
  • 1970-01-01
  • 2011-06-14
相关资源
最近更新 更多