2013-07-21 41 views
0

我正在嘗試使用名稱空間和結構&遇到問題。編譯器如何爲此結構分配內存?

C++ 

#include<iostream> 
using namespace std; 

namespace One 
{ 
    struct Data 
    { 
     int val; 
     char character; 
    }; 
} 

namespace Two 
{ 
    struct Data 
    { 
     int val; 
     bool boolean; 
    }; 
} 

void functionOne(void) 
{ 
    using namespace One; 
    cout << "functionOne()" << endl; 
    cout << "The size of struct Data : "; 
    cout << sizeof(Data) << endl; 
} 

void functionTwo(void) 
{ 
    using namespace Two; 
    cout << "functionTwo()" << endl; 
    cout << "The size of struct Data : "; 
    cout << sizeof(Data) << endl; 
} 

int main() 
{ 
    functionOne(); 
    functionTwo();  
} 

Output 
functionOne() 
The size of struct Data : 8 
functionTwo() 
The size of struct Data : 8 

雖然當我改變了代碼「命名空間的兩個」於以下內容:

namespace Two 
{ 
    struct Data 
    { 
     char val; 
     bool boolean; 
    }; 
} 

Output : 

functionOne() 
The size of struct Data : 8 
functionTwo() 
The size of struct Data : 2 

我無法弄清楚編譯器如何分配內存的結構。提前致謝。

+0

@CarlNorum鏈接中的答案提到了32位體系結構。我能否知道(通常)在64位體系結構上進行對齊? –

+0

什麼樣的問題? –

+0

@mozart,這可能與您的示例相同。 –

回答

5

這裏的問題最有可能是由於對齊要求。如果我沒有弄錯,結構是根據其成員的最大對齊要求來對齊的。在你的結構的第一個版本中,你有int; char;。它看起來在你的機器上int是以4字節對齊的,所以編譯器在char之後加了3個字節的結構。在第二個版本中,您只有bool; char;,它們都是1個字節的大小,並且對齊到1個字節(在您的機器上),所以編譯器不需要填充任何東西,因此大小可以回落到2。

我在「您的機器上」指定,因爲這可能因多種因素而異。

讓我們製作一個漂亮的圖表!

// One::Data (version 1) 
0    4    5    7 
[int (size 4), char (size 1), padding (size 3)][...] 
// Because of alignment restrictions on int, this needs a padding of 3 bytes 

// Two::Data (version 1) 
0    4    5    7 
[int (size 4), bool (size 1), padding (size 3)][...] 
// Because of alignment restrictions on int, this needs a padding of 3 bytes 

// One::Data (version 2), no change 

// Two::Data (version 2) 
0    1    2 
[char (size 1), bool (size 1)][...] 
// No alignment restrictions, therefore no padding is required 
+0

對於第二個命名空間的更改版本,它爲什麼分配8個字節?是3個字節用作填充? –

+0

@mozart我在看你的問題,改變後的版本是2號? – Borgleader

+0

是的,它是大小爲2. –

2

官方的答案,編譯器如何分配內存是 「然而就是了」。有幾個限制,但不是 很多。然而,在這種情況下,你所看到的是邏輯上的: 邏輯上:許多類型具有(或可能具有)對齊限制 ,並且必須放置在某個地址的值爲 的倍數。這些限制傳播到任何類別 其中包含該類型的成員,否則,您 無法尊重類成員的對齊方式。顯然, 你的機器上,bool的大小爲1(和char必須有一個 大小的1),並int的大小爲4,並且還必須在4。因此,一個地址多在One::Data對齊 和Two::Data, 你有一個int,接着charbool,隨後填充的 足夠的字節,以使結構的 4.(原則上多的總大小,char/bool和 填充能按任何順序混合,但實際上,我見過的每個編譯器都會在任何聲明之後放置填充。)

由於既不是bool也不是char具有任何取向 限制,存在其中 僅包含每個中的一個的類不需要填充。

請注意,這取決於機器和編譯器。在 某些機器(例如Sun Sparc或IBM大型機)訪問 未對齊的值將導致硬件陷阱,編譯器幾乎需要對齊(並插入填充) 。另一方面,在英特爾的 上,未對齊的訪問可以正常工作,但有明顯的性能影響;編譯器通常會在這裏強制對齊 (並且Windows和Linux二進制API都需要它),但編譯器可能會忽略它,以及一些非常早期的英特爾 編譯器,當內存比現在更緊密時,編譯器會返回。 (這實際上是一個有趣的問題,因爲 在現代機器上的性能最高,如果你有一個大的 陣列和其中一個結構,那麼額外的內存訪問應該是 的錯位可能會從緩存中解決,或者 即使是從內存讀取管道,幾乎沒有額外的成本,而對象的較小尺寸可能導致較少的緩存 未命中,從而更好的性能。但我沒有采取任何措施, ,所以我只是猜測。)

還有一點需要注意的是,該標準要求類別 成員按順序分配。從技術上講,只有當它們之間沒有 訪問說明符時,但實際上,所有編譯器 總是按順序分配它們。所以,如果你有一個像類:

struct T 
{ 
    double d1; 
    char c1; 
    double d2; 
    char c2; 
}; 

會(典型值)的大小爲32,其中如:

struct T 
{ 
    double d1; 
    double d2; 
    char c1; 
    char c2; 
}; 

只會有一個大小的24早在天當內存是 緊張,我們經常關注這樣的事情,但現在 地方有時是一個問題,也許它會支付再次這樣做 :按大小的順序聲明變量,最大的 首先。