我们都知道位字段不是很便携,因此应该避免引用C99标准6.7.2.1/10 - “结构和联合说明符”;
实现可以分配足够大的任何可寻址存储单元来保存位域。如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中。如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的。单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的。可寻址存储单元的对齐未指定。
然而;在处理硬件设备等时,通常需要处理特定的位布局,这些布局在没有位字段的情况下意味着令人讨厌且难以理解(至少在我看来)比特代码。
所以我想做的是使用位字段,但是我想首先验证编译器生成的位字段布局,实际上符合我的期望。所以我正在做的是写一些static_asserts,在这种情况下,布局不匹配会失败。
例如;一个简单的大小断言;
struct bitField
{
bool AC : 1; // Accessed bit. Just set to 0. The CPU sets this to 1 when the segment is accessed.
bool RW : 1; // Readable bit/Writable bit. Is the code segment readable / data segment writeable.
bool DC : 1; // Direction bit/Conforming bit. 0=the segment grows up. 1=the segment grows down.
bool EX : 1; // Executable bit. If 1 code in this segment can be executed, ie. a code selector. If 0 it is a data selector.
bool DT : 1; // Descriptor type (Always 1?).
uint8_t DPL : 2; // Descriptor privilege level, 2 bits. - Contains the ring level, 0 = highest (kernel), 3 = lowest (user applications).
bool P : 1; // Present bit. - Is segment present? (1 = Yes). This must be 1 for all valid selectors.
};
static_assert(sizeof(bitField)==1, "Incorrect size of bitfield");
这可以作为一个魅力,并确保位字段总是正确的大小,但由于位字段的实现特定性质,我不能假设位字段内部的布局是否正确。所以我要做的是,static_assert比特字段的布局;
// Used to check that the bitfield, matches a specific required layout
union Bitfield_Layout_Checker
{
constexpr Bitfield_Layout_Checker(uint8_t raw) : raw(raw) {}
constexpr bitField getBitField()
{
return format;
}
uint8_t raw;
bitField format;
};
constexpr bool isBitfieldOkay()
{
return Bitfield_Layout_Checker(0x01).getBitField().P == true;
}
static_assert(isBitfieldOkay(), "Bitfield layout not okay");
所以这个测试,应该检查当前位是否在正确的位置。 - 但是在尝试编译上面的代码时,使用GCC v4.8.1会产生此错误消息;
main.cpp:35:5: error: non-constant condition for static assertion
static_assert(isBitfieldOkay(), "Bitfield layout not okay");
^
main.cpp:35:34: in constexpr expansion of ‘isBitfieldOkay()’
main.cpp:32:58: in constexpr expansion of ‘Bitfield_Layout_Checker(1).Bitfield_Layout_Checker::getBitField()’
main.cpp:35:5: error: accessing ‘Bitfield_Layout_Checker::format’ member instead of initialized ‘Bitfield_Layout_Checker::raw’ member in constant expression
使用Clang v3.1产生此错误消息;
a.cpp:35:19: error: static_assert expression is not an integral constant expression
static_assert(isBitfieldOkay(), "Bitfield layout not okay");
^~~~~~~~~~~~~~~~
a.cpp:23:20: note: read of member 'format' of union with active member 'raw' is not allowed in
a constant expression
return format;
^
a.cpp:23:20: note: in call to 'bitField(1.format)'
a.cpp:32:16: note: in call to ')'
return Bitfield_Layout_Checker(0x01).getBitField().P == true;
^
a.cpp:35:19: note: in call to 'isBitfieldOkay()'
static_assert(isBitfieldOkay(), "Bitfield layout not okay");
^
这表明当通过原始字段初始化时,我不允许读出联合的格式字段。那么有什么方法可以解决这个问题吗?