繁体   English   中英

编译器如何确定位域结构的大小?

[英]How does compiler determine the size of a bitfield struct?

例如:

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

为什么?

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

指定一个位域; 它的长度是通过冒号从位字段名称中设置的。 bit-field属性不是类成员类型的一部分。 常量表达式应为具有大于或等于零的值的整数常量表达式。 常量表达式可能大于位域类型的对象表示(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个字节。

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

如果你想(需要)依赖于对方。 (比如网络头处理)你需要使用#pragma push,pop。

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

struct {
...
} __attribute__(packed)

这将迫使编译器压缩它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM