6

例如:

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_ 应该具有相同的长度,但似乎不是。

为什么?

4

2 回答 2

6

标准(工作草案的9.6 )是这样说的:

指定一个位域;它的长度由冒号从位域名称开始。位域属性不是类成员类型的一部分。常量表达式应该是一个整数常量表达式,其值大于或等于 0。常量表达式可能大于位字段类型的对象表示 (3.9) 中的位数;在这种情况下,额外的位被用作填充位并且不参与位域的值表示 (3.9)。类对象内的位域分配是实现定义的。位域的对齐是实现定义的. 位域被打包到一些可寻址的分配单元中。[注意:位域在某些机器上跨越分配单元,而不在其他机器上。位域在某些机器上从右到左分配,在其他机器上从左到右分配。——尾注]

(我的重点)

所以这将取决于你的编译器。在您的情况下似乎发生的事情 - 我会描述为相当正常的行为 - 它只是组合相同类型的位域,然后将结构打包到 4 字节边界,所以在第一种情况下,我们有:

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 个字节。

于 2013-09-04T10:33:26.223 回答
0

它是特定于编译器的,编译器正在执行各种对齐以优化对字段的访问。

如果你想(需要)依靠对齐。(如网络头处理)你需要使用#pragma push,pop。

或者 __ 属性 __(packed) - 这是一个 GCC 扩展。

struct {
...
} __attribute__(packed)

这将强制编译器压缩它。

于 2013-09-04T10:34:10.443 回答