除了第一个与打包结构不同的全打包字段的 C 结构吗?
Is a C struct of all-packed fields except first one different from packed struct?
在其 Common Type Attributes 中,GCC 提供 packed
:
This attribute, attached to a struct
[...] type
definition, specifies that each of its members (other than zero-width
bit-fields) is placed to minimize the memory required. This is
equivalent to specifying the packed
attribute on each of the members.
此外,根据 C18 标准 (§ 6.7.2.1, 15-17):
Within a structure object, the non-bit-field members [...] have addresses that increase in the order in
which they are declared. A pointer to a structure object, suitably
converted, points to its initial member [...], and vice versa.
There may be unnamed padding within a structure object, but not at its
beginning. [...] There may be unnamed padding at the end of a structure [...].
因此,鉴于结构的开头没有填充,在其第一个成员上使用 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)编译两个 struct
,它们似乎总是共享相同的布局。
如果第一个成员没有打包,它仍然有它原来的对齐要求,可能大于一个字节,因此结构至少有那个对齐要求,这也可能需要在末尾填充结构。
对于:
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。
在其 Common Type Attributes 中,GCC 提供 packed
:
This attribute, attached to a
struct
[...] type definition, specifies that each of its members (other than zero-width bit-fields) is placed to minimize the memory required. This is equivalent to specifying thepacked
attribute on each of the members.
此外,根据 C18 标准 (§ 6.7.2.1, 15-17):
Within a structure object, the non-bit-field members [...] have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member [...], and vice versa. There may be unnamed padding within a structure object, but not at its beginning. [...] There may be unnamed padding at the end of a structure [...].
因此,鉴于结构的开头没有填充,在其第一个成员上使用 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)编译两个 struct
,它们似乎总是共享相同的布局。
如果第一个成员没有打包,它仍然有它原来的对齐要求,可能大于一个字节,因此结构至少有那个对齐要求,这也可能需要在末尾填充结构。
对于:
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。