有没有办法避免联合的“过度补偿”对齐?

问题描述

我有一个看起来像这样的结构:

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

我希望sizeof(Foo)等于16,但在64位计算机上sizeof(Foo)24。我认为这是因为size_t强制将并列的对齐方式设为8,因此1之后buff7之后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的值,反之亦然。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...