2016-11-23 36 views
2

我想分配一些內存,將其初始化爲一些值,然後將此內存的不同部分轉換爲不同的結構。東西如下:將內存投射到工會

union structA{ 
    __int8 mem[3]; 

    struct{ 
    unsigned field1 : 8; 
    unsigned field2 : 12; 
    unsigned field3 : 4; 
    }; 
}; 

struct structB{ 
    __int8 mem[10]; 
}; 


__int8 globalMem[128]; 

structA a1 <---- &globalMem[0] 
structA a2 <---- &globalMem[10] 
structB b1 <---- &globalMem[30] 

我嘗試使用reinterpret_cast的,我沒有得到任何編譯器錯誤,但似乎我的變量(a1a2b1)並沒有真正分配/正確初始化。

任何有關爲什麼這不起作用的想法和什麼是實現這樣的事情的正確方法?

謝謝!

+4

位域對齊和填充是實現定義的。您將需要調查您的編譯器是否在位域中添加了填充到結構中。極有可能。 –

+0

也使用一個簽名的基礎類型('__int8')可能不是最好的主意。 –

+1

試圖用 '編譯包(推,1) 編程 編譯包(彈出)' 它應該消除任何填充問題,如山姆Varshavchik提到的。 – GoldenSpecOps

回答

0

要達到什麼樣的,你打算做需要使用reinterpret_cast的:

structA a1 = *reinterpret_cast<structA*>(&globalMem[0]); 
structA a2 = *reinterpret_cast<structA*>(&globalMem[10]); 
structB b1 = *reinterpret_cast<structB*>(&globalMem[30]); 

這有什麼錯呢?

這需要格外小心,因爲C++ struct是一種特殊的class,而且這種分配的不尊重對象的語義(因爲在不同globalMem地址的內容是不是正確的對象,除非你初始化」 d在你的代碼中使用placement new)。

在使用這種技巧之前,您還可以確保structA是可複製的(is_trivially_copyable<structA>::value,幸運的是這裏是真的)。

此外,對齊約束可能存在問題,因爲globalMem沒有對齊約束,但根據編譯器/體系結構的不同,structA可能需要字對齊。

最後,structA的大小不一定是3,因爲你傾向於這樣想。事實上在某些編譯器將是4,如this online demo

其他的看法

你可以使用標準類型uint8_t,而不是編譯器特定類型的名稱以雙下劃線。

關於對齊和大小主題,我建議你對內存佈局假設非常謹慎。我寧願建議你的globalMem考慮將它作爲它包含的所有結構的結構,以確保正確的對象語義並且具有安全的佈局。

+0

但這隻會將globalMem的一部分複製到a1等。它實際上不會將a1,a2和b1「映射」到globalMem的某些部分。 – Ali

+0

@Ali在你的佈局中有幾個問題(見編輯),這讓我認爲你的映射控制採取了錯誤的假設(從struct A的大小開始)。我邀請你看看這個在線演示:http://ideone.com/K3PYpT,你會發現prpeprly初始化的對象被正確複製,儘管重新解釋轉換。但是,重新解釋演員通常會出現一個值得重新考慮的棘手設計。 – Christophe