有没有办法让 union "over-compensate" 对齐?

Is there a way to not have a union "over-compensate" alignment?

我的结构如下所示:

class Foo {
    union {
        size_t cap;
        char buff[15];
    };
    bool isHeap;
}; 

我希望 sizeof(Foo) 等于 16,但 sizeof(Foo) 在 64 位计算机上是 24。我认为这是因为 size_t 强制联合的对齐方式为 8,因此在 buff 之后有 1 浪费字节,在 [ 之后有 7 =22=]。我想到了这个解决方案:

class Foo {
    union{
        struct {
            size_t cap; 
            char ignore[7]; 
            bool isHeap1;
        }; 
        struct {
            char buff[15]; 
            bool isHeap2
        };
    };
};

但它依赖于未定义的行为,因为您不知道是否要检查 isHeap1isHeap2,直到您已经访问了它们的值之一。
有没有办法不浪费那些依赖未定义行为的字节?


作为旁注,我想不出这个问题的真正好名字,如果有人能想到一个更好的名字那就太好了。如果有人建议更好的名字,或者如果你们认为它已经是一个合理的名字,我会删除这条评论。

您可以将 packed 属性添加到 union 以强制它为 15 个字节,然后包含 class 将是 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++ 中的 ill-formed。

But it relies on undefined behavior as you don't know whether to check isHeap1 or isHeap2 until you have already accessed one of their values.

如果成员的顺序是灵活的,那么这将是一个定义明确的替代方案:

union {
    struct {
        bool isHeap;
        size_t cap; 
    } s1; 
    struct {
        bool isHeap;
        char buff[15]; 
    } s2;
};

这是允许访问联合体的非活动成员的特殊情况:两个标准布局结构的公共初始序列。换句话说,即使 s1 是活动成员,阅读 s2.isHeap 也是明确定义的,并且会导致 s1.isHeap 和 vice-versa 的值。