2017-01-18 36 views
1

我正在閱讀Game Coding Complete第4版。有一個關於內存對齊的主題。在下面的代碼中,作者說第一個結構非常慢,因爲它不是位對齊的,也不是字節對齊的。第二個不是位對齊,而是字節對齊。最後一個在快速,因爲它是兩個。他說,如果沒有編譯指示,編譯器會調整內存本身,導致內存浪費。我無法真正理解計算。C/C++中的內存對齊

這是從文本某些部分: -

如果編譯器被留下通過加入未使用的字節以優化SlowStruct, 每個結構將是24個字節,而不是僅僅14.七個額外字節 後填充第一個字符變量,剩餘的字節添加在結尾。這確保了 整個結構始終以8字節的邊界開始。這大約是浪費空間的40%,這全部歸因於成員變量的粗心排序。

這是以粗體顯示的結束行: - 不要讓編譯器浪費寶貴的內存空間。把你的一些腦細胞放到 的工作中,並調整你自己的成員變量。

請給我演示計算並更清楚地解釋文本中的填充概念。

代碼: -

#pragma pack(push, 1) 
struct ReallySlowStruct 
{ 
    char c : 6; 
    __int64 d : 64; 
    int b : 32; 
    char a : 8; 
}; 

struct SlowStruct 
{ 
    char c; 
    __int64 d; 
    int b; 
    char a; 
}; 

struct FastStruct 
{ 
    __int64 d; 
    __int b; 
    char a; 
    char c; 
    char unused[2]; 
}; 
#pragma pack(pop) 
+2

_it既不是位對齊也不是字節aligned_。位對齊?我沒有得到這個,C中最小的可尋址地址是一個字節,不是嗎? –

+2

相關/ dupe:http://stackoverflow.com/questions/5397447/struct-padding-in-c和http://stackoverflow.com/questions/6025269/data-structure-padding – NathanOliver

+1

也請參閱這個wiki:https: //en.wikipedia.org/wiki/Data_structure_alignment – NathanOliver

回答

1

書中給出的例子是高度依賴於所使用的編譯器和計算機體系結構。如果你在自己的程序中測試它們,你可能會得到完全不同於作者的結果。我將假定一個64位架構,因爲作者也根據我在說明中讀到的內容。 讓我們看看一個例子由一個:

ReallySlowStruct 如果所使用的編譯器支持非字節對齊的結構成員,「d」開始的將是在該結構的第一個字節的第七位。聽起來非常適合節省內存。這個問題是,C不允許位尋址。因此,要將newValue保存到「d」成員,編譯器必須執行大量的位移操作:將「newValue」的前兩位保存在byte0中,向右移6位。然後將「newValue」兩位移到左邊並從字節1開始保存。字節1是一個不對齊的內存位置,這意味着大容量內存傳輸指令將不起作用,編譯器必須一次保存每個字節。

SlowStruct 它變得更好。編譯器可以擺脫所有的詭計。但是寫入「d」將仍然需要一次寫入每個字節,因爲它不與原始「int」大小對齊。 64位系統上的本地大小爲8,因此每個不能被8除的內存地址一次只能訪問一個字節。更糟糕的是,如果我關閉打包,我將浪費大量內存空間:每個跟着int的成員都將填充足夠的字節,以使整數在可以被8除的內存位置開始。在這種情況下:char a和c都會佔用8個字節。

FastStruct 這與目標機器上的int大小對齊。 「b」應該佔用8個字節。由於字符都捆綁在一個地方,編譯器不會填充它們,也不會浪費空間。字符每個只有1個字節,所以我們不需要填充它們。完整的結構加起來就是一個16字節的整體大小。除以8,所以不需要填充。

+1

謝謝你回答我的問題。就在現在,我運行了一些來自不同鏈接的代碼,並在書中給出了實驗,並且在主題上明確指出,沒有特別的標準決定了填充。但作者暗示要提高性能,請以適當的方式瞭解編譯器填充規則和順序聲明。你的回答也非常有幫助。謝謝。 –

+0

我在FastStruct代碼中犯了錯誤。我忘了添加64個int var。對不起。請相應地更新答案。 –

+0

謝謝你糾正答案。我感謝你的幫助,現在我相信我已經理解了這個話題。再次感謝。 –