英文:
Packed struct size is 40 even though member sizes add to 36
问题
结构体 K
是经过打包的,其所有成员变量的大小之和为 36。每个成员都有一个 static_assert
来检查这一点。
然而,K
本身的大小是 40,而不是 36。K
不是多态的等等。
为什么 K
不是大小为 36?
我使用的是 Clang 16。我不知道一种简单的方法来可视化这个结构体,否则我就会尝试了。如果有人可以推荐一种方法,那将非常棒。
英文:
struct K
is packed and the sum of it's class member sizes is 36. Each member has a static_assert
checking this.
However, the size of K
itself is 40, not 36. K isn't polymorphic etc.
Why is K
not size 36?
Using Clang 16. I'm not aware of an easy way to visualize the struct, or I would have. If anyone can recommend a way that would be great.
template<class S>
struct P
{};
struct D : public P<D>
{
uint64_t x_;
};
enum class E : uint8_t
{};
struct K
{
D a_;
D b_;
uint64_t c_;
uint64_t d_;
uint16_t e_;
E f_;
E g_;
static_assert(sizeof(a_) == 8); // Passes
static_assert(sizeof(b_) == 8); // Passes
static_assert(sizeof(c_) == 8); // Passes
static_assert(sizeof(d_) == 8); // Passes
static_assert(sizeof(e_) == 2); // Passes
static_assert(sizeof(f_) == 1); // Passes
static_assert(sizeof(g_) == 1); // Passes
}__attribute__((packed));
static_assert(sizeof(K) == 36); // Fails, is 40 instead of 36
int main()
{
K f;
}
答案1
得分: 2
启用了clang的警告后,问题变得明显:
<source>:17:7: 警告:由于其为非POD,因此不将字段'a_'打包为布局目的[-Wpacked-non-pod]
17 | D a_;
| ^
<source>:18:7: 警告:由于其为非POD,因此不将字段'b_'打包为布局目的[-Wpacked-non-pod]
18 | D b_;
| ^
GCC和clang似乎都没有记录这种行为(请参见GCC packed
属性,clang packed
属性),但看起来使用继承(从P<D>
)会禁用packed
对成员的影响。
在这种情况下,没有固有的理由为什么D
不能被打包,它似乎只是一个普遍的禁令。
如果任何成员未打包,为了确保所有成员的正确对齐,结构需要额外的填充。K
的对齐方式是8
,如下所示:
static_assert(alignof(K) == 8); // 通过;打包类型的正常对齐方式通常为1
由于K
对齐到8字节,并且其成员的组合大小为36,因此必须在末尾添加4个填充字节,以正确对齐K
到8字节(将其大小增加到40)。
另请参阅
英文:
With warnings enabled for clang, the issue becomes obvious:
<source>:17:7: warning: not packing field 'a_' as it is non-POD
for the purposes of layout [-Wpacked-non-pod]
17 | D a_;
| ^
<source>:18:7: warning: not packing field 'b_' as it is non-POD
for the purposes of layout [-Wpacked-non-pod]
18 | D b_;
| ^
Neither GCC nor clang seem to document this behavior (see GCC packed
attribute, clang packed
attribute), but it looks like using inheritance (from P<D>
) disables the effect of packed
for a member.
There is no inherent reason why D
couldn't be packed in this case, it simply appears to be a general ban.
If any member isn't packed, to ensure proper alignment of all members, the struct
requires additional padding. The alignment of K
is 8
, as evidenced by:
static_assert(alignof(K) == 8); // passes; alignment is normally 1 for packed types
Since K
is aligned to 8 bytes, and the combined size of its members is 36, 4 padding bytes have to be added at the end to correctly align K
to 8 bytes (by increasing its size to 40).
See Also
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论