2013-12-18 43 views
4

我們知道,有在A大小的不同,當你定義A這樣的:內存對齊優化也是內存大小

class A 
{ 
    short a; 
    double b; 
    short c; 
}; 

或類似這樣的

class A 
{ 
    short a; 
    short c; 
    double b; 
}; 

我假設我們正在編譯32位操作系統,並且我們告訴編譯器對齊到32位。

編譯器是否真的很難通過實現相同的性能來重新排序定義以獲得最小大小?

+0

使用'__attribute__((__packed __))' – Mine

+0

這是我想要的解決方案嗎?這是不是這樣的大小問題?默認選項?(如果不是,那麼爲什麼?如果是,那麼謝謝:)!) – Narek

+2

還要考慮多模塊編譯的後果。如果一個模塊重新排序而另一個模塊不重新排序 – Mysticial

回答

4

這是非常困難的。特別需要一個結構來按照與結構定義完全相同的順序排列字段。

這個要求可能是對帕斯卡沒有這樣的要求和造成令人驚訝的結果的反應。

無論如何,並非所有的CPU架構都需要對齊或填充。在大多數情況下,它會導致輕微的性能損失。在現代處理器的時代,由於CPU管道的其他方面,內存提取中額外的一個或兩個週期可能會消失。

+0

我同意大部分答案,而不是「額外的一個或兩個週期」:有些處理器根本不支持不對齊的提取,因此如果使用'__attribute __(),則需要多指令序列來訪問未對齊的字段。 (__packed __))'結構。對齊是有原因的。另外,如果結構打包在需要對齊的體系結構上,則無法可靠地採用指向結構成員的指針。 –

+0

@JoeZ:我記得68000非常適合它惱人的未對齊內存陷阱。幸運的是,這些限制在現代CPU中越來越不常見。即使8086也不會因未對齊的16位訪問而發生故障:只需花費更長的時間。如果您想充分利用5 MHz揚聲器,那麼您可以對齊這些詞。 – wallyk

+0

x86處理器處理不對齊,當然。 ARM處理器不會啓用適當的功能位。 (至少對於ARMv7來說就是這樣。)如果嘗試在錯誤的對齊邊界加載SSE類型,我相信即使是x86錯誤。 –

1

不難爲編譯器,它是由標準方式禁止(有一個例外): 第9.2.12:(非聯合)的

非靜態數據成員類沒有聲明 中間訪問說明符被分配,以便後面的成員在類對象中具有更高的地址 。的由接入說明符分離 非靜態數據成員分配的順序是不確定的

例外是,具有不同的訪問修飾符成員可以是reorderes這樣:

class A 
{ 
public: 
    int a; 
    int b; 
private: 
    int c; 
int d; 
{'\; 

a和b,無法重新排序。 c和d不能重新排序,但(a和b)可以重新排序(c和d)

0

由於標準的要求(粗略地說:唯一的,遞增的地址和分組的C++類,編譯器無法重新排序通過訪問修飾符)。

這就是爲什麼重新排序需要手工完成。 通常,您在這裏很幸運:現有數據類型的更好對齊意味着更小的尺寸和更好的性能,這裏沒有任何限制。

但是,有時較大的數據(元素)大小意味着更簡單的指令。例如,使用位字段來削減幾個字節意味着更復雜的代碼,代碼大小和數據大小之間存在折衷;將內部循環增加500字節以削減2k數據對於代碼的優化和內存局部性可能是災難性的。

像PVS Studio這樣的工具可以發出警告當結構元素順序不是最理想的並且可以改進時。


[EDIT2]至於「爲什麼這些規則的存在」

TL;博士:這是有趣的,但並不重要,它只是好奇着想。

優先(從另一無情拷貝SO回答)的標準的相關部分:

內的結構對象,非位字段構件和單元,其中位字段駐留有地址即增加他們宣佈的順序。指向適當轉換的結構對象的指針指向其初始成員(或者如果該成員是位域,則指向它所在的單位),反之亦然。結構對象中可能有未命名的填充,但不在其開頭。

指向標準佈局結構對象的指針,適當地使用reinterpret_cast進行轉換,指向其初始成員(或者如果該成員是位字段,則指向其駐留的單元),反之亦然。 [注意:因此在標準佈局結構對象中可能存在未命名的填充,但在開始時並不需要填充,以實現適當的對齊。末端注]

(請注意,這涉及到C,C++是更復雜一點。)

的標準說一點關於原因,大多是 「猜測」 在這裏:

獨特的地址是由標準的其他問題產生的要求。

製作指向結構類型轉換的指針 - 等價於指向第一個成員的指針當然是由於現有的編程習慣。 (它允許「數據polymorphy」用C通過嵌套「基地結構」爲「衍生結構」的第一部件)由程序員指定

保留的順序

的「香草猜測」不會破壞數據局部的手工優化。將最常訪問的成員置於頂層可以改善結構中的局部性(允許更好的緩存或更短的尋址指令)。如果編譯器重新排序,那麼對於總體結構大小相對小的增益,這些優化可能會丟失。

C++需要通過訪問說明分組:(即「所有公共瓦爾在一起,所有受保護的乏在一起,所有的私人瓦爾在一起):我從來沒有發現一個理由(我必須說,它是一個有點出人意料)我可以想象,(可能)意圖是允許編譯器實現利用硬件訪問控制(「這段代碼可能無法訪問那塊內存」)。OTOH我知道沒有任何體系結構可以使得控制,我從來沒有見過訪問說明符被認爲是一個安全的機制。

+0

我在哪裏可以閱讀更多關於標準的這些要求的原因? – Narek