在基类中保留内存以在派生类c++中使用

问题描述 投票:0回答:1

我正在编写一些低级抽象来通过 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 吗?我真的不需要使用多态性,如果我无法修复多态性行为,那么我想以某种方式阻止它,最好是在编译时。 这可能吗?

c++ struct undefined-behavior derived-class bit-fields
1个回答
0
投票

问题在于变量定义

FaultsStatusRegister reg;

不初始化任何成员。所有字段都将具有“不确定”值。以任何方式使用不确定的值都会导致未定义的行为 你需要例如

FaultsStatusRegister reg{};

对所有成员进行零初始化。

另一方面,在位字段中共享“字”的位顺序是由实现指定的。它在一个编译器中可能与下一个编译器不同。更不用说字节序问题了。

© www.soinside.com 2019 - 2024. All rights reserved.