问题描述
我有一个看起来像这样的结构:
class Foo {
union {
size_t cap;
char buff[15];
};
bool isHeap;
};
我希望sizeof(Foo)
等于16
,但在64位计算机上sizeof(Foo)
是24
。我认为这是因为size_t
强制将并列的对齐方式设为8
,因此1
之后buff
和7
之后isHeap
浪费了字节{1}}。我想到了这个解决方案:
class Foo {
union{
struct {
size_t cap;
char ignore[7];
bool isHeap1;
};
struct {
char buff[15];
bool isHeap2
};
};
};
但是它依赖于未定义的行为,因为您不知道要检查isHeap1
还是isHeap2
,直到您已经访问了它们的值之一。
有没有办法不浪费那些不依赖未定义行为的字节?
顺便提一下,如果有人能做得更好,那我就想不出这个问题的好名字了。如果建议使用更好的名称,或者大家都认为它已经是一个合理的名称,我将删除此评论。
解决方法
您可以将packed
属性添加到联合以将其强制为15个字节,然后包含的类将为16个字节:
class Foo {
union __attribute__((packed)) {
size_t cap;
char buff[15];
};
bool isHeap;
};
,
struct { size_t cap; char ignore[7]; bool isHeap1; };
C ++没有匿名结构。这是C ++中的错误形式。
但是它依赖于未定义的行为,因为在您已经访问过isHeap1或isHeap2的值之一之前,您都不知道要检查它们。
如果成员的顺序灵活,那么这将是一个明确定义的替代方案:
union {
struct {
bool isHeap;
size_t cap;
} s1;
struct {
bool isHeap;
char buff[15];
} s2;
};
这是允许访问联合的不活动成员的特殊情况:两个标准布局结构的公共初始序列。换句话说,即使s1
是活动成员,也清楚地定义了s2.isHeap
的读取,并导致s1.isHeap
的值,反之亦然。