bit fields - Bitfields and C++11 static_assert -
we know bit-fields not portable, , therefore should avoided, quote c99 standard 6.7.2.1/10 - "structure , union specifiers";
an implementation may allocate addressable storage unit large enough hold bitfield. if enough space remains, bit-field follows bit-field in structure shall packed adjacent bits of same unit. if insufficient space remains, whether bit-field not fit put next unit or overlaps adjacent units implementation-defined. order of allocation of bit-fields within unit (high-order low-order or low-order high-order) implementation-defined. alignment of addressable storage unit unspecified.
however; in dealing hardware devices , such, 1 have deal specific bit-layouts, which, without bit-fields, imply nasty , unreadable (at-least in opinion) bit-fiddling code.
so i'd do, use bit-fields, i'd first validate bit-field layout compiler generates, matches expectations. i'm in process of doing, writing static_asserts, fails, in case, layout doesn't match.
for instance; simple size assertion;
struct bitfield { bool ac : 1; // accessed bit. set 0. cpu sets 1 when segment accessed. bool rw : 1; // readable bit/writable bit. 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 segment can executed, ie. code selector. if 0 data selector. bool dt : 1; // descriptor type (always 1?). uint8_t dpl : 2; // descriptor privilege level, 2 bits. - contains ring level, 0 = highest (kernel), 3 = lowest (user applications). bool p : 1; // present bit. - segment present? (1 = yes). must 1 valid selectors. }; static_assert(sizeof(bitfield)==1, "incorrect size of bitfield");
this works charm, , ensures bit-field of correct size, due implementation specific nature of bit-fields, can't assume whether layout inside of bit-field correct. i'm trying is, static_assert layout of bit-field;
// used check bitfield, matches 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");
so test, supposed check present bit, in correct place. - when trying compile above code, using gcc v4.8.1 yields, error message;
main.cpp:35:5: error: non-constant condition 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
using clang v3.1 yields, error message;
a.cpp:35:19: error: static_assert expression not integral constant expression static_assert(isbitfieldokay(), "bitfield layout not okay"); ^~~~~~~~~~~~~~~~ a.cpp:23:20: note: read of member 'format' of union active member 'raw' not allowed in constant expression return format; ^ a.cpp:23:20: note: in call 'bitfield(1.format)' a.cpp:32:16: note: in call ')' return bitfield_layout_checker(0x01).getbitfield().p == true; ^ a.cpp:35:19: note: in call 'isbitfieldokay()' static_assert(isbitfieldokay(), "bitfield layout not okay"); ^
which indicates i'm not allowed read out format field of union, when has been initialized through raw field. there way around this?
i not recommend using bitfields if wish deal hardware. tagged c++11
have std::bitset
makes comfortable access individual bits inside fixed length:
class register { public: void setac(bool level) { m_register[0] = level; } bool getac() { return m_register[0]; } void setrw(bool level) { m_register[1] = level; } bool getrw() { return m_register[1]; } /* other setters , getters... */ void setdpl(uint8_t val) { std::bitset<2> valbits(val); m_register[5] = valbits[0]; m_register[6] = valbits[1]; } uint8_t getdpl() { std::bitset<2> bits; bits[0] = m_register[5]; bits[1] = m_register[6]; return bits.to_ulong(); } /* other setters , getters... */ uint8_t getregister() { return m_register.to_ulong(); } private: std::bitset<8> m_register; };
but can create struct
of std::bitset
this:
struct bitfield { std::bitset<1> ac; std::bitset<1> ac; std::bitset<1> rw; std::bitset<1> dc; std::bitset<1> ex; std::bitset<1> dt; std::bitset<2> dpl; std::bitset<1> p; };
the problem second example more complicated assemble , send hardware.
Comments
Post a Comment