我正在编写一些低级抽象来通过 SPI 与某些芯片进行通信,并且我创建了寄存器抽象以避免棘手的位操作。我认为我可以创建包含将寄存器结构转换为 uint16_t 的方法的接口,当我从寄存器结构的实例调用该方法时它工作正常,但是当我将其称为接口方法时,我得到了未定义的行为 - 我怀疑这是因为接口/abstract 不为实际字段保留内存。
#include <cstdio>
#include <cstdint>
// interface struct
struct IRegister {
[[nodiscard]] constexpr uint16_t asU16() {
return *std::bit_cast<uint16_t*>(this);
}
};
//Register struct - i have like 20 of those, thats why i used interface
struct FaultsStatusRegister : IRegister {
uint16_t CS_OCP_FLT_PHASE_A : 1;
uint16_t CS_OCP_FLT_PHASE_B : 1;
uint16_t CS_OCP_FLT_PHASE_C : 1;
uint16_t CP_FLT : 1;
uint16_t DVDD_OCP_FLT : 1;
uint16_t DVDD_UV_FLT : 1;
uint16_t DVDD_OV_FLT : 1;
uint16_t BK_OCP_FLT : 1;
uint16_t OTS_FLT : 1;
uint16_t OTW_FLT : 1;
uint16_t LOCK_FLT : 1;
uint16_t WD_FLT : 1;
uint16_t OTP_FLT : 1;
uint16_t Reserved : 3;
};
int main()
{
FaultsStatusRegister reg;
reg.CS_OCP_FLT_PHASE_C = 1;
reg.CS_OCP_FLT_PHASE_A = 1;
reg.CS_OCP_FLT_PHASE_B = 1;
reg.OTP_FLT = 1;
printf("%b \n", reg.asU16()); //This if fine: 1000000000111
IRegister ireg = reg;
printf("%b \n", ireg.asU16()); // UB? : 11100000000
return 0;
}
我该如何解决这个问题?或者我可以以某种方式阻止使用导致不良行为的 IRegister 吗?我真的不需要使用多态性,如果我无法修复多态性行为,那么我想以某种方式阻止它,最好是在编译时。 这可能吗?
问题在于变量定义
FaultsStatusRegister reg;
不初始化任何成员。所有字段都将具有“不确定”值。以任何方式使用不确定的值都会导致未定义的行为。 你需要例如
FaultsStatusRegister reg{};
对所有成员进行零初始化。
另一方面,在位字段中共享“字”的位顺序是由实现指定的。它在一个编译器中可能与下一个编译器不同。更不用说字节序问题了。