struct
K
已打包,其类成员大小的总和为 36。每个成员都有一个 static_assert
检查这一点。
但是,
K
本身的大小是40,而不是36。K不是多态的等等。
为什么
K
不是36号?
使用 Clang 16。我不知道有一种简单的方法来可视化结构,或者我会的。如果有人能推荐一种方法那就太好了。
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;
}
启用 clang 警告后,问题变得显而易见:
<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_;
| ^
GCC 和 clang 似乎都没有记录此行为(请参阅 GCC
packed
属性、clang packed
属性),但看起来使用继承(来自 P<D>
)会禁用 packed
的效果成员。
在这种情况下,没有任何内在原因导致D
无法打包,这只是一个普遍的禁令。
如果有任何成员未包装,为了确保所有成员正确对齐,
struct
需要额外的填充。 K
的对齐是 8
,证明如下:
static_assert(alignof(K) == 8); // passes; alignment is normally 1 for packed types
由于
K
对齐到 8 字节,并且其成员的组合大小为 36,因此必须在末尾添加 4 个填充字节,以将 K
正确对齐到 8 字节(通过将其大小增加到 40)。