2016-01-14 67 views
6

我一直使用以下範例用於遍歷靜態定義的數組在C:數組元素計數用C

struct foo { ... }; 
struct foo array[10]; 

for (int i; i < sizeof(array)/sizeof(array[0]); i++) 
    ... 

的,那麼,這個工作每次到目前爲止;-)

但它使奇蹟,可這不破,如果結構實際上是長度不自然對齊,例如:

struct foo { long a; char b; }; 

不應該編譯器決定sizeof(struct foo) == 7雖然sizeof(array) == 32由於對齊(LP64數據模型)?

+0

如果我的假設是真實的,我正在尋找一個規範的參考,或者如果我的假設並不總是成立的話,我會找一個反例。 –

+1

BTW是一個整數除法,它不能給你錯誤的數字。我錯了嗎? – LPs

+0

「_S不應該由編譯器決定'sizeof(struct foo)== 7'_」不一定,可以有填充。 – emlai

回答

5

如約sizeof操作者的C99 standard, section 6.5.3.4狀態:

當應用於具有數組類型的操作數,其結果是該陣列中的字節 總數。

和:

實施例2 sizeof運算符的另一個用途是計算元件的陣列中的數 :

 `sizeof array/sizeof array[0]` 

所以陣列的大小將總是是其元素大小的倍數。

和約結構相同的段:

當施加到具有結構或聯合類型的操作數時, 結果是字節的總數在這樣一個對象,包括 內部和後填充。

+1

同樣來自標準:「當應用於具有結構或聯合類型的操作數時,結果是此類對象中的總字節數**,包括內部和尾部填充**」 – dbush

+1

@dbush將它添加到答案如果你不介意.. –

4

數組中沒有「死區」如果有填充,則包含,其中的大小爲struct

+0

看起來你是對的錢,我可以用gcc的'__attribute __((packed))'來調整結構大小,例如'__attribute __((aligned(128)))'但是無論我對數組做什麼,它都是數組的常量倍數。 –

1

sizeof宏返回您的結構的大小包括所有填充。對於靜態定義的struct數組,這仍然是正確的。所以聲明:

sizeof(struct array)/sizeof(struct array[0]) 

無論每個struct元素中有多少個或什麼類型的成員,總會允許您遍歷數組元素。

包裝/對準使得對於數組邊界
沒有差別,即使pragma pack指令在源所使用的,可能導致包裝改變(這也可以影響對準),從而產生一個不同的值對於數組中的每個結構元素的sizeof,數組元素的計數保持不變

...或者一個反例,如果我的假設並不總是持有

要注意這一點很重要
sizeof運營工作不同的陣列結構的(或任何其他類型),實際上是指針,在堆上動態創建。例如,如果您有:

typedef struct { ... }FOO; 
FOO *foo; 
... 
foo = malloc(10*sizeof(FOO)); 
size_t size = sizeof(foo); //returns sizeof pointer, (4 bytes on 32 bit target) 
          //No matter how many, or what type members make up the struct 

因此

sizeof(struct foo)/sizeof(struct foo[0]) 

將不再給你數組元素的正確計數。

2

成員的結構內部對齊不會影響該結構的數組。因此,不管結構體包含什麼成員或它們是如何對齊的,你擁有的東西都可以保證工作。

如果有該結構的構件之間的填充,那麼它的對所有結構陣列的元件是相同的。 sizeof(array)總是可以被sizeof(array[0])整除。

所以計算陣列大小的方法中,

size_t len = sizeof(array)/sizeof(array[0]); 

保證只要array一個陣列任何類型工作。

1

編譯器可以自由地在成員之間和結尾處的結構體中插入填充,但第一個成員的偏移必須始終爲零。

另一方面,陣列總是必須是連續的,元素之間沒有任何「空白」。該標準規定:

數組類型描述了連續分配的非空的對象集

通常,大多數編譯器將在結構的末尾插入一些填充,以確保當連續佈局在數組中,第二個元素不會破壞某些成員的對齊要求。典型的規則是結構的總大小必須擴展到可以通過最大對齊要求的成員對齊平均分配的大小。

在LP64模式,sizeof(long)是8和sizeof(char)是1 long將需要8字節對齊,char沒有對齊要求。大小的總和應爲9,但編譯器會將結構的大小擴展到16,因此16 % 8 == 0。這樣,一個相鄰的數組元素將從一個可以被8整除的位置開始,所以第一個成員的對齊將被保留。