更改派生类中压缩结构的位大小

change bit size of packed struct in derived class

本文关键字:结构 压缩 派生      更新时间:2023-10-16

现有代码:

typedef unsigned int uint;
Class A
{
union xReg
    {
        uint allX;
        struct
        {
            uint x3      : 9;
            uint x2      : 9;
            uint x1      : 14;
        }__attribute__((__packed__)) __attribute__((aligned(4)));
    };
};

我的要求:现在,我需要从a派生一个类,在派生的类中,x1、x2和x3的比特大小必须改变。

我该怎么做?谢谢你的帮助!

编辑

我有一个类(比方说a(,大约有7-8个并集(每个并集代表HW寄存器(,以及大约20个(大约(函数。这些函数中的大多数创建这些并集的实例,并使用位(在我的示例中为x1、x2、x3等(。

现在,我的要求是为一个新硬件添加代码,该硬件具有95%的相同功能。这些变化包括寄存器位大小的变化,以及一些功能的变化。因此,在20个函数中,至少有5个函数需要更改才能更改实现。这就是我选择继承并覆盖这些函数的原因。

剩下的15个功能,唯一的变化就是比特大小的变化。所以,我不想覆盖这些函数,而是使用基类函数。但是,寄存器(并集(的位大小应该改变。我该怎么做?

在C++中,不能更改派生类中的位字段长度。

然而,您可以尝试使用bit_field长度来参数化您的类。

template <size_t N1, size_t N2, size_t N3 = 32 - N1 - N2>
struct myStruct
{
    uint bitField1 : N1;
    uint bitField2 : N2;
    uint bitField3 : N3;
};

现在,您可以用任意N1、N2、N3实例化结构,例如:

myStruct<9, 9> s;

对于给定的设计,你无法解决它。问题是,虽然你可以派生和重写方法,但数据成员不能被重写,派生类中未被重写的成员访问字段的方式与他们访问字段的方法完全相同,结果是你会在不同的地方使用不同的大小。

运行时多态性

我没有考虑太多设计,但第一种简单的运行时方法是重构所有现有的代码,这样它们就不用直接访问字段,而是通过访问器(settersgetters(来访问字段,并将参数映射到存储类型。您可以覆盖这些访问器,并且函数不取决于每个位字段的确切大小。消极的一面是,使访问者虚拟化意味着将有一个性能实例,因此您可以考虑

编译时(或静态(多态性

您可以重构类,使其成为一个以并集类型为参数的模板。这样,您就可以在当前设计中的派生类中使用不同的并集来实例化模板。添加新的成员函数(如果你想使用成员函数(就不那么简单了,你可能最终不得不使用CRTP或其他方法来创建实现的基础,同时允许你专门化扩展它。

template <typename R>
class A
{
   R xReg;
public:
   unsigned int read_x1() const {
       return xReg.x1;
   }
// rest of implementation
};
union xReg1 {
   unsigned int all;
   struct {
      unsigned int x3 : 9;
      unsigned int x2 : 9;
      unsigned int x1 : 14;
   };
};
union xReg2 {
   unsigned int all;
   struct {
      unsigned int x3 : 8;
      unsigned int x2 : 9;
      unsigned int x1 : 15;
   };
};
int main() {
   A< xReg1 > initial;
   std::cout << initial.access_x1() << std::endl;
   A< xReg2 > second;
   std::cout << second.access_x1() << std::endl;
}

考虑到您的额外问题陈述,Armen建议的变体可能适用。这里听起来似乎不需要实际的继承,只需要一些重用公共代码的方法。

例如,您可能根本不想要成员函数。

template<typename reg>
union hardware_register {
    unsigned all;
    struct {
        unsigned i : reg::i;
        unsigned j : reg::j;
        unsigned k : reg::k;
    };
};
template<typename hardware>
void print_fields(const hardware& hw) {
   cout << hw.i << " " << hw.j << " " << hw.k << endl;
}
//this method needs special handling depending on what type of hardware you're on
template<typename hardware>
void print_largest_field(const hardware& hw);
struct register_a {
    static const unsigned i = 9;
    static const unsigned j = 4;
    static const unsigned k = 15;
};
struct register_b { 
    static const unsigned i = 4;
    static const unsigned j = 15;
    static const unsigned k = 9;
};
template<>
void print_largest_field<register_a>(const register_a& a) {
    cout << a.k << endl;
}
template<>
void print_largest_field<register_b>(const register_b& b) {
    cout << b.j << endl;
}
int main() {
    hardware_register<register_a> a;
    hardware_register<register_b> b;
    print_fields(a);
    print_fields(b);
    print_largest_field(a);
    print_largest_field(b);
}

或者,您可以将所有通用功能打包到一个模板基类中。您从该基类派生,并实现所需的任何特殊行为。

template<typename HW> 
struct base {
    void print_fields {
        cout << hw.i << hw.j << hw.k << endl;
    };
private:
    HW hw;
};
struct hw_a : base<register_a> {
    void print_largest_field {
        cout << hw.k << end;
    }
};
struct hw_b : base<register_b> {
    void print_largest_field {
        cout << hw.j << end;
    }
};

您可以为不同类型的寄存器提供多个模板参数,或者扩展底层特征结构,使其一次定义多个寄存器。