例如:
struct a {
uint32_t foreColor_ : 32;
uint32_t backColor_ : 32;
uint16_t lfHeight_ : 16;
uint16_t flags_: 4;
bool lfBold_: 1;
bool lfItalic_: 1;
bool lfUnderLine_: 1;
bool lfDashLine_: 1;
bool lfStrike_: 1;
bool lfSubscript_: 1;
bool lfSuperscript_: 1;
};
是16个字节,但
struct a {
uint32_t foreColor_ : 32;
uint32_t backColor_ : 32;
uint16_t lfHeight_ : 16;
uint8_t flags_: 4;
bool lfBold_: 1;
bool lfItalic_: 1;
bool lfUnderLine_: 1;
bool lfDashLine_: 1; //for ime
bool lfStrike_: 1;
bool lfSubscript_: 1;
bool lfSuperscript_: 1;
};
长12个字节。
我认为flags_应该有相同的长度,但似乎没有。
为什么?
答案 0 :(得分:6)
标准(the working draft的9.6)说明了这一点:
指定位字段;它的长度是从位字段名称中设置的 通过冒号。位字段属性不是类型的一部分 班级成员。常量表达式应该是一个整数 常量表达式,其值大于或等于零。该 常量表达式可能大于中的位数 对象表示( 3.9)比特字段的类型;在这种情况下,额外的比特用作填充比特,不参与值表示( 3.9)位域。 类对象中位域的分配是实现定义的。位域的对齐是 实现定义即可。比特字段被打包成一些可寻址的字段 分配单位。 [注意:位字段跨越一些分配单元 机器而不是其他机器。位字段从右到左分配 一些机器,从左到右在其他机器上。 - 后注]
(我的重点)
所以它取决于你的编译器。在您的情况下似乎正在发生的事情 - 我将其描述为相当正常的行为 - 是它只是组合相同类型的位域然后将结构打包到4字节边界,所以在第一种情况下我们有:< / p>
struct a {
uint32_t foreColor_ : 32; // 4 bytes (total)
uint32_t backColor_ : 32; // 8 bytes
uint16_t lfHeight_ : 16; // 10 bytes
uint16_t flags_: 4; // 12 bytes
bool lfBold_: 1; // 13 bytes
bool lfItalic_: 1;
bool lfUnderLine_: 1;
bool lfDashLine_: 1;
bool lfStrike_: 1;
bool lfSubscript_: 1;
bool lfSuperscript_: 1; // still 13 bytes
};
然后填充到16个字节,在第二个字节中我们有:
struct a {
uint32_t foreColor_ : 32; // 4 bytes (total)
uint32_t backColor_ : 32; // 8 bytes
uint16_t lfHeight_ : 16; // 10 bytes
uint8_t flags_: 4; // 11 bytes
bool lfBold_: 1; // 12 bytes
bool lfItalic_: 1;
bool lfUnderLine_: 1;
bool lfDashLine_: 1;
bool lfStrike_: 1;
bool lfSubscript_: 1;
bool lfSuperscript_: 1; // still 12 bytes
};
哪个不需要填充,并保持12个字节。
答案 1 :(得分:0)
它是特定于编译器的,编译器正在进行各种对齐以优化对字段的访问。
如果你想(需要)依赖于对方。 (比如网络标题处理)你需要使用#pragma push,pop。
或__ attribute __(packed) - 这是一个GCC扩展名。
struct {
...
} __attribute__(packed)
这将迫使编译器压缩它。