2014-11-23 69 views
5

很明顯,在C cannot insert padding between their elements中的數組。但是,是否有任何規則說他們不能在整個陣列的尾端處添加尾部填充?數組可以有尾部填充嗎?

即,這個程序保證在任何地方都能得到相同的結果嗎?

#include <stdio.h> 
int main(void) { 
    typedef char a[3]; 
    typedef a b[3]; 
    printf("%zu %zu\n", sizeof(a), sizeof(b)); // -> 3 9 
} 

至於我可以工作,加入了尾隨字節或五的a大小,也許在一個錯誤的優化的嘗試,就不會突破數組訪問規則(b[1][1]仍然恰好映射到*(&b + sizeof(a) * 1 + 1)不管其包含的a對象的大小,並且訪問超出所包含的a的長度是UB)。

我找不到在C標準中的任何地方,它實際上直接說數組的大小是元素類型的大小乘以元素的數量。 6.5.3.4只說sizeof返回數組中的「字節數」(它確實給出sizeof array/sizeof array[0]作爲代碼示例,但它只是一個示例 - 它並不是說它必須工作,它不給出任何細節)。

隱式保證對於編寫依賴於確切數據佈局的便攜式代碼很有用,例如,經過打包的RGB值:

typedef uint8_t RGB[3]; 
RGB * data = ...; 
glColorPointer(3, GL_UNSIGNED_BYTE, 0, data); 

(OK這樣的OpenGL可以接受步幅值,所以這是一個壞榜樣,但你明白了吧)

對於這個問題,我從廣泛的概念(即使假設標準中的例子),你可以用sizeof得到一個數組元素的數量,無論如何這在任何地方都可能是真的 - 是否有任何已知的情況?

+0

填充的含義是使數據對齊。在你的情況下,我相信所有3的char數組的大小都是3,但如果你在之後聲明一個int,那麼可能會有1或5個填充。一個好的c編譯器不會做額外的工作,這很難預測。但如果您談論的是可移植性,我認爲最好是在目標平臺上重新編譯代碼,或者如果平臺差異很大,則可以進行交叉編譯。 – HuStmpHrrr 2014-11-23 19:36:48

+0

「,並沒有給出任何細節」 - 它確實說計算數組中的元素數量。你說得對,那只是一個例子,而這個例子並不是規範的。 – hvd 2014-11-23 19:39:26

+0

通過查看後續子句,可以間接推斷出數組沒有這種填充:「當應用於具有結構或聯合類型的操作數時,結果是此類對象中的總字節數,包括內部和尾部填充。」 - 在結構和聯合中顯式引用了填充,而在數組中缺少這種引用使我相信數組中不能有這種填充。 – 2014-11-23 19:41:32

回答

6

我認爲標準從未認爲有必要明確說明數組沒有填充,因爲簡單的理由是這樣的填充對於任何實現都是有用的。

也就是說,我確實相信標準通過==運算符的描述禁止這種填充。

6.5.9相等運算

語義

6兩個指針比較相等當且僅當[...]或一個是一個指針 到一個過去的端部一個數組對象,另一個是指向不同數組對象的開始的指針,該對象恰好緊跟地址空間中的第一個數組對象。

鑑於

int array[2][2]; 

表達&array[0][2]點是一個指針一個過去的第一陣列子對象的端部。 &array[1][0]是一個指向第二個數組子對象的指針,它緊跟在內存中的第一個數組之後。這些指針需要比較相等。如果int[2]有尾部填充,如果sizeof(int[2]) > 2 * sizeof(int),我無法想象任何實現如何使兩個指針比較相等。

+0

斑點,+1。 – 2014-11-23 19:54:08