簡體   English   中英

更改派生 class 中打包結構的位大小

[英]change bit size of packed struct in derived class

現有代碼:

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 派生一個 class,並且在派生的 class 中,x1、x2 和 x3 的位大小必須更改。

我該怎么做呢? 謝謝你的幫助 !

編輯

我有一個 class(比方說 A)大約。 7-8 個聯合(每個代表硬件寄存器)和大約 20 個(大約)函數。 這些函數中的大多數創建這些聯合的實例,並使用位(在我的示例中為 x1、x2、x3 等)。

現在,我的要求是為具有 95% 功能的新硬件添加代碼。 這些變化包括寄存器位大小的變化,以及一些功能的變化。 因此,在 20 個函數中,我至少需要更改 5 個函數才能更改實現。 這就是我要 select inheritance 並覆蓋這些功能的原因。

rest 15個功能,唯一變化的是位大小變化。 所以,我不想覆蓋這些函數,而是使用基本的 class 。 但是,寄存器(聯合)的位大小應該改變。 我怎么做?

您不能在 C++ 中更改派生 class 中的位字段長度。

但是,您可以嘗試使用 bit_field 長度參數化您的 class。

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;

使用給定的設計,您無法解決它。 問題是,雖然您可以派生和覆蓋方法,但不能覆蓋數據成員,派生 class 中未覆蓋的成員將以與它們完全相同的方式訪問該字段,結果是您將在不同的地方使用不同的尺寸。

運行時多態性

我對設計沒有多想,但第一個簡單的運行時方法將重構所有現有代碼,以便通過訪問器( settergetter )而不是直接訪問字段,並且 map arguments 到存儲類型。 您將能夠覆蓋這些訪問器,並且這些函數將不依賴於每個位域的確切大小。 不利的一面是,訪問器是虛擬的意味着會有一個性能實例,所以你可以考慮

編譯時(或靜態)多態性

您可以重構 class ,使其成為一個模板,將聯合類型作為參數。 這樣,您可以在當前設計中使用不同的聯合實例化模板,即派生的 class。 添加新成員函數(如果您想使用成員函數)不會那么簡單,您最終可能不得不使用 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 建議的變體可能適用。 聽起來好像您在這里不需要實際的 inheritance,只是一些重用一些通用代碼的方法。

例如,您可能根本不需要成員函數。

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

或者,您可以將所有常用功能封裝到模板化基礎 class 中。 您從該基礎 class 派生,並實現您需要的任何特殊行為。

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

您可以為不同類型的寄存器提供多個模板參數,或擴展底層特征結構,使其一次定義多個寄存器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM