2012-02-28 84 views
1

我正在處理的項目需要向用戶表示許多不同的硬件寄存器作爲類對象。我幾乎完成了我的對象模型,但是我有一個障礙,我不知道如何超越。這些寄存器使用結構暴露。所有這些寄存器結構都將從一個基本結構繼承,這將提供有用的東西,例如如何從內存獲取特定的寄存器值並將其存儲到位域。使用這個指針指向一個類中的位字段

現在,好的是所有這些寄存器都很好地對齊DWORD。所以,我的代碼是這樣的:

struct Base { 
    DWORD offset; 
    Driver* pToDrv; 

    // methods to set/get values to the registers using the driver pointer 
    void SetRegister(DWORD val); 
}; 


struct Register1 : public Base { 
    DWORD bit0   : 1; 
    DWORD bit1   : 1; 
    // etc. until 32 bits 
    DWORD bit31   : 1; 

    // getters/setters for the individual bits 

    void SetFullRegister(DWORD val) { 
     *(reinterpret_cast<DWORD*>(this)) = val; // uh-oh! This doesn't point to bitfield 
     SetRegister(reinterpret_cast<DWORD*>(this)); // same thing here 
    } 
}; 

我與這個指向基本實例在派生對象的方法使用,即使在較小的程序更簡單的方法驗證。我如何確保這個指向我正在嘗試執行的操作的派生對象的開始?

我嘗試以下方法:

*(reinterpret_cast<DWORD*>(this + sizeof(Derv))) = val; 

雖然沒什麼不好貌似發生了,最終的結果是什麼都沒有發生過。我知道這是不正確的,因爲價值被分配到某個地方,但是,畏縮,我不知道在哪裏。這顯然不起作用,也不是一種安全的方法。

如果我沒有充分描述我的問題,請讓我知道。

感謝, 安迪

回答

1

您的對象模型不能正確代表寄存器的內容

您的註冊有一個偏移量,一個驅動程序和內容。後者對於每種類型的寄存器可以具有不同的佈局,因此不能被繼承,但應該基於每個寄存器來定義。

嵌套類是一個合適的方法來做到這一點。

struct Register1 : public Base { 
    struct Content { 
     DWORD bit0   : 1; 
     DWORD bit1   : 1; 
     // etc. until 32 bits 
     DWORD bit31   : 1; 
    } content; 

    // getters/setters for the individual bits 

    void SetFullRegister(DWORD val) { 
     *(reinterpret_cast<DWORD*>(&content)) = val; // This points to bitfield 
     SetRegister(reinterpret_cast<DWORD*>(&content)); // same thing here 
    } 
}; 
+0

謝謝。我相信這種方法解決了這個問題。我知道我忽略了一個簡單的答案。這在我測試的縮小版本中起作用。現在,爲了與更大,更醜陋的程序集成在一起。 – 2012-02-28 20:52:58

2

可能是你應該使用工會?

struct Register1 : public Base { 
    union { 
     struct Bits { 
     DWORD bit0   : 1; 
     DWORD bit1   : 1; 
     // etc. until 32 bits 
     DWORD bit31   : 1; 
     }; 
     DWORD dwReg; 
    } Reg; 

    // getters/setters for the individual bits 

    void SetFullRegister(DWORD val) { 
     Reg.dwReg = val; 
    } 
}; 
+1

不!只能從最後寫入的類型中讀取聯合。如果這個工作,它的實現定義。 (哦,是的,我知道每個人都這樣做,它不是C++。) – xtofl 2012-02-28 18:15:23

+0

除了在SO(http://stackoverflow.com/a/740686/6610)對標準的一些引用,我發現了一個真實的案例Qt代碼:http://qt.gitorious.org/qt/qt/commit/c1b067ea8169e1d37e2a120334406f1f115298bb – xtofl 2012-02-28 18:47:31

+0

非常有趣,謝謝!找到關於此提交的詳細文章 - http://labs.qt.nokia.com/2011/06/10/type-punning-and-strict-aliasing/ – 2012-02-28 20:37:53

1

我只想在這裏使用一個聯盟:

union RegisterValue { 
    struct { 
    DWORD bit0 : 1; 
    // ... 
    }; 
    DWORD Full; 
}; 

另一件事:我不認爲你應該混合的高層次結構,如繼承和低層次的結構,如位字段。我建議製作一個POD RegisterValue結構體/聯合體並將它作爲接口類的成員。

+0

同意混合迴避。不同意聯盟片斷,這是非標準的,因此不能保證「重新解釋」一個值。 – xtofl 2012-02-28 18:18:52

0

你只要看看你的struct s的地址,就好像它們是DWORD s一樣,冒着與vtables等類似的風險。爲什麼不做一個union的竅門:創建一個帶位域的struct,並在union內加上DWORD。你會以這種方式安全。

0

似乎你在做很多事情,同時,這使得很難解決這篇文章的主要問題。

你不能直接指向特定的位。你可以模擬一個位指針。如前面的回答,告訴你,你正在混合指針,位域,結構體,方法指針類&類。就我個人而言,我並不使用「結構」作爲「C++公共類」,而是使用「純粹的結構」。請注意,位可以用作邏輯/布爾類型,並且大多數c/C++編譯器提供「bool」庫(「sdbool.h」「<stdbool>」,「bool.h」)。

// "pure c" style 
struct registertype 
{ 
     DWORD bit0   : 1; 
     DWORD bit1   : 1; 
     // etc. until 32 bits 
     DWORD bit31   : 1; 
}; 

// "c++" wrapper style 
class registerclass 
{ 
    registertype data; 

    public: 
    registerclass (DWORD fullvalue) 
    { 
    // assign values to each bit 
    } 

    bool getBit(int bitnumber) 
    { 
    // recover value from a specific bit 
    } 

    void setBit(int bitnumber, bool BitValue) 
    { 
    // assign values to a specific bit 
    } 
}; 

說實話,有時候,我用無符號整數,而不是位字段,特別是,如果位域的陣列,是必需的,其necesary使用較少的內存可能。

乾杯。

相關問題