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

时间:2011-07-01 17:24:04

标签: c++ struct unions packed

现有代码:

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个功能,只是改变是位大小的变化。所以,我不想覆盖这些函数,而是使用基类函数。但是,寄存器(联合)的位大小应该改变。我该怎么做?

3 个答案:

答案 0 :(得分:3)

您无法在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;

答案 1 :(得分:1)

使用给定的设计无法解决问题。问题是虽然你可以派生和覆盖方法,但是数据成员不能被覆盖,派生类中未被覆盖的成员将以与他们正在做的完全相同的方式访问该字段,结果是你将成为在不同的地方使用不同的尺寸。

运行时多态性

我对设计没有太多考虑,但第一个简单的运行时方法是重构所有现有代码,以便不是直接访问字段,而是通过访问器( setters )来实现和 getters ),并将参数映射到存储类型。您将能够覆盖这些访问器,并且函数不依赖于每个位域的确切大小。从负面来看,让访问者变为虚拟意味着会有一个性能实例,所以你可以考虑

编译时间(或静态)多态

您可以重构该类,以便它是一个模板,将union作为参数的类型。这样,您可以使用与当前设计中的派生类不同的联合来实例化模板。添加新的成员函数(如果你想使用成员函数)不会那么简单,你可能最终不得不使用CRTP或其他方法来创建实现的 base ,同时允许你用专业化来扩展它。

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;
}

答案 2 :(得分:0)

鉴于您的其他问题陈述,可能适用于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;
    }
};

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