2012-11-08 22 views
18

假設我有一些類型T必須是N字節對齊。現在,我宣佈T類型的數組:與包含的類型相比,C++是如何對齊的?

T array[size]; 

請問陣列具有相同的排列要求T型或將其有任何其他對齊要求?

+2

我很好奇,爲什麼這很重要? – Pubby

+2

@Pubby:我正在審查代碼,並且我發現了一些關於數組和對齊要求的非常好奇的評論,我幾乎可以肯定的是評論是blsht,但是想要驗證。 – sharptooth

回答

15

是的,對齊要求必須是相同的。顯然,一列T必須至少與單個T一樣嚴格對齊,否則其第一個成員將不會正確對齊。數組不能更嚴格地與其元素類型對齊的事實來自標準部分8.3.4,其說明數組是連續分配的元素子對象。考慮一下這個數組的數組:

T a[2][size]; 

不管的size值,可以有兩個數組a[0]a[1]之間沒有「額外」的填充,否則這違反了contiguosly分配要求。我們知道(char*)&a[1] == (char*)&a[0] + sizeof(a[0])sizeof(a[0]) == sizeof(T[size]) == size * sizeof(T)。因爲這適用於任何size,所以必須可以在任何地址上放置一個T的數組,該數組適合單個對象(給定足夠的地址空間)。

+0

據我所知,如果子數組的大小是對齊的倍數,那麼對齊可能與元素不同,因爲不需要填充。 [這個評論](http://stackoverflow.com/users/147192/matthieu-m)似乎是正確的答案。 – Pubby

+0

[Whoops,this link](http://stackoverflow.com/questions/13284208/how-is-an-array-aligned-in-c-compared-to-a-type-contained/13284631#comment18111863_13284297) – Pubby

+0

' T [2]'可以與'alignof(T)* 2'對齊,這將允許'T [2] [size]'沒有任何填充。 – Pubby

4

我相信陣列的對齊需求將與陣列元素的對齊需求相同。

顯然,數組的起始位置必須至少與第一個元素所要求的一樣嚴格,所以它的對齊要求不能不那麼嚴格。

數組的起始地址加上每個元素的大小必須使第二個元素充分對齊。這對元素類型的大小有一個約束,我相信這意味着填充可以在結構的末尾引入,以保持數組對齊,即使你從不在數組中使用該結構。但這並不意味着需要更嚴格的協調。

通過歸納法,如果前兩個元素都是OK的,後續元素都可以,因此給數組提供與其元素相同的對齊要求應該很好。但是,從規範中引用將是很好的。

+6

這裏你去(對齊)**§5.3.6[expr.alignof] ** 1 /一個'alignof'表達式產生其操作數類型的對齊要求。操作數應該是* type-id *,表示一個完整的對象類型或其數組。[...] 3/[...]當對數組類型應用'alignof'時,結果應該是元素類型。 –

+0

任何「填充」必須反映在'sizeof';不在數組中的元素必須與不在數組中的元素具有相同的大小。至於第二點,我不認爲標準否認數組有權比非數組類型有更嚴格的對齊要求(我相當肯定C++ 03,它沒有太多關於對齊開始),但實際上,對齊要求將是相同的。 –

+0

對齊要求將相同,但有一個明顯的例外情況。一個'new char [n]'(其中'char'實際上可以是任何字符類型)的返回值必須與任何適合'n'的類型對齊。但是,請注意,此保證僅適用於「新」表達式;它不適用於'char []'類型的變量。 –

1

規則是相同的我相信但解釋可能會混淆。

我相信,因爲數組的每個元素將具有相同的大小,所以只有對齊第一個元素會自動對齊其餘元素,因此在元素之間永遠不會有任何填充。

這可能是真實的情況下一個微不足道的數組,但不適用於複雜的情況。

陣列的步幅可能大於元素大小,即每個單獨元素之間可能存在襯墊。

下面是一個很好的例子

struct ThreeBytesWide { 
    char a[3]; 
}; 

struct ThreeBytesWide myArray[100]; 

source - stride wikipedia

ThreeBytesWide陣列的每個元素都能夠被排列到四個字節邊界

編輯:所闡述的意見,提在單個元素之間有襯墊的時候,元素本身就是3個字節,並且與4個字節的邊界對齊。

+0

該文章具有誤導性,因爲有關C/C++行爲的消息來源。在其Talk頁面中:C和C++中的「stride」和sizeof()總是相同的,即sizeof(T [N])== sizeof(T)* N。例如參見ISO14882的8.3.4: 2003(e)或ISO9899:1999(e)的6.5.2.1以及ISO9899:1999(e)的6.5.6和ISO9899:1999(e)的6.2.5-20; ISO9899的6.5.3.4-6 :1999(e)在這裏很有趣。「 –

+0

陣列中沒有填充。如果結構在四個字節的邊界對齊,我們還會在每個結構的末尾有'sizeof(ThreeBytesWide)== 4',並且有一個未使用的字節。 –

+0

我不知道我完全理解這兩個意見。 @BoPersson我也在說sizeof(ThreeBytesWide)會是4.所以對於一個單獨的數組,除了第一個字節之外不會有填充,除非它被封裝在一個像上面那樣的結構中。 – fayyazkl

-1

對象數組需要是連續的,所以在對象之間不會有填充,儘管填充可以添加到對象的末尾(產生幾乎相同的效果)。 C++ Data Member Alignment and Array Packing

#include <iostream> 

__declspec(align(32)) 
struct Str1 
{ 
    int a; 
    char c; 
}; 

template<typename T> 
struct size 
{ 
    T arr[10]; 
}; 


int main() 
{ 
    size<Str1> b1; 

    std::cout << sizeof(Str1) << std::endl; // prints 32 
    std::cout << sizeof(b1) << std::endl; // prints 320 

    std::cin.ignore(); 
    return 0; 
} 

參考文獻:

  1. Data alignment in C++, standard and portability
  2. http://msdn.microsoft.com/en-us/library/83ythb65.aspx
+0

這並沒有說明數組本身的對齊方式,只是關於大小。 – sharptooth

相關問題