我正在研究一些用于小型微控制器(AVR)的C ++代码。我们使用了
struct MCU
表示MCU的寄存器布局。在过去,所有寄存器都是uint8_t
类型,我们使用提供的cpp
制造商 - 宏来设置个别位。这不是C ++方式......
我们引入了ControlRegister
类模板:它可以使用可接受的值类型进行参数化:
template<typename Component, typename BitType, typename ValueType = uint8_t>
struct __attribute__((packed)) ControlRegister final {
typedef Component component_type;
typedef ValueType value_type;
typedef BitType bit_type;
template<typename... Flags>
void inline set(Flags... f) {
static_assert((std::is_same<bit_type, Flags>::value && ... && true), "wrong flag type");
static_assert(sizeof...(Flags) <= 8, "too much flags");
value_type v = (static_cast<value_type>(f) | ... | 0);
assert(Util::numberOfOnes(v) == sizeof... (Flags));
hwRegister = v;
}
template<BitType... Flags>
void inline add() {
static_assert(sizeof...(Flags) <= 8, "too much flags");
constexpr auto v = (static_cast<value_type>(Flags) | ... | 0);
constexpr auto n = Util::numberOfOnes(v);
static_assert(n == sizeof... (Flags), "use different flags");
hwRegister |= v;
}
private:
volatile value_type hwRegister;
};
某些MCU寄存器具有双重用途,例如:设置定时器预分频器和其他一些中断信息。预分频器位在几个地方使用,我们认为将寄存器分成两个或多个类似于特定寄存器结构的部分会更好。因为这基本上是相同的记忆位置,所以想到使用联合的想法:
struct MCU final {
struct CompA {
enum class Flags1 {
f1 = (1 << 0),
f2 = (1 << 1)
};
enum class Flags2 {
f1 = (1 << 1),
f2 = (1 << 2)
};
union {
ControlRegister<CompA, Flags1> part1;
ControlRegister<CompA, Flags2> part2;
} __attribute__ ((packed));
};
};
part2
- 成员可以是前面提到的预分频器组件:可以在多个位置使用相同的值类型Flags
。
我已经阅读了几篇关于C ++中的联合的帖子,但是如果这个代码片段产生UB,我仍然没有明确的解释。
查看g ++的汇编语言输出会导致假设,它没问题。但我不确定......!
int main() {
const auto c = reinterpret_cast<MCU::CompA*>(0x28);
using F1 = MCU::CompA::Flags1;
c->part1.set(F1::f1, F1::f1); // writing
using F2 = MCU::CompA::Flags2;
c->part2.set(F2::f1);
c->part2.add<F2::f2>(); // reading
while(true) {}
}