2013-02-28 42 views
4

從實驗(在鐺和GCC,與-O2和-O0)是似乎,在下面的代碼未提及的結構字段*是否始終被初始化爲零(即當結構在堆棧上時)?

typedef struct foo_s { int i; int j; } foo_t; 
int main(void) { 
    foo_t foo = {.i = 42}; 
    ... 

foo.j是自動爲零。

是否由C99保證,還是編譯器特定的實現細節?

注意:我甚至試圖在堆棧下面的無效內存中寫入0xFFs,在後面給出的foo地址處。

更新:有幾條評論指出,這只是因爲堆棧下方的內存碰巧包含零。下面的代碼確保不是這種情況,並且可以證明GCC -O0正在調零內存。

-7和-6的偏移量與編譯器相關。他們需要在鏗鏘中有所不同。

typedef struct foo_s { int i; int j; } foo_t; 

int main(void) { 
    int r; 
    int *badstack0 = &r - 7; 
    int *badstack1 = &r - 6; 

    *badstack0 = 0xFF; // write to invalid ram, below stack 
    printf("badstack0 %p, val: %2X\n", badstack0, *badstack0); 
    *badstack1 = 0xEE; // write to invalid ram, below stack 
    printf("badstack1 %p, val: %2X\n", badstack1, *badstack1); 

    // struct test 
    foo_t foo = {.i = 42}; 
    printf("&foo.i %p\n", &foo.i); 
    printf("&foo.j %p\n", &foo.j); 
    printf("struct test: i:%i j:%i\n", foo.i, foo.j); 
    return 0; 
} 

輸出:

badstack0 0x7fff221e2e80, val: FF 
badstack1 0x7fff221e2e84, val: EE 
&foo.i 0x7fff221e2e80 
&foo.j 0x7fff221e2e84 
struct test: i:42 j:0 

回答

9

如果你提供任何initialisers,就好像它們是靜態的沒有明確提及的成員被初始化。這是通過在6.7.9(19)的標準保證:

在初始化列表順序應發生的初始化,設置用於特定的子對象重寫爲同一子對象任何前面列出的初始化每個初始化; 所有未明確初始化的子對象都應隱式初始化,它們與具有靜態存儲持續時間的對象相同。

(重點由我加)

如果不初始化任何成員,所有成員的值是不確定的。

+0

值得一提的是,在特定的情況下,OP在程序的開頭只是有一個歸零堆棧區域,並且它的'j'成員的值爲'0'。 – 2013-02-28 14:45:33

+5

不,即使堆棧區域未被清零,OP也有'foo_t foo = {.i = 42};'明確初始化一個成員。因此,其他成員必須初始化爲0,就好像它是一個'static int j;'。 – 2013-02-28 14:52:29

+0

@Daniel Fischer IBM說的相反嗎? http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fstrin.htm「temp_address.postal_code取決於存儲類temp_address變量;如果它是靜態的,則該值將爲NULL。「 – fadedbee 2013-02-28 15:13:26

4

C保證只要至少有一個數組/結構體/聯合體*中的至少一個成員被初始化,那麼所有其他成員將被初始化,就像他們有靜態存儲持續時間一樣,正如Daniel Fischer的答案中所引用的那樣。換句話說,所有其他成員自動設置爲零或NULL。

數組/結構體/聯合體的存儲類型不重要,它們根據相同的規則進行初始化,無論它們是否具有自動或靜態存儲持續時間。

這不是C99或更高版本獨有的東西,C有總是有此要求。所有符合規範的C編譯器都遵循此規則,它是規範的而不是實現定義的。

這與「調試版」無關。

由於事實上,這個規則就是爲什麼你可以通過編寫

int array[100] = {0}零整個陣列的解釋。

這段代碼的意思是「初始化第一個元素爲零,然後初始化其餘99個元素,就好像它們具有靜態存儲時間,即使它們爲零」。


(*)這三種類型在C標準中正式命名爲「聚合類型」。

+0

Daniel Fischer的答案應該被接受爲正確答案。我的回答僅在OP編輯後添加了更多詳細信息。 – Lundin 2013-02-28 15:16:26

+0

如果工會的第一個成員不是最大的,那麼標準對其他成員的初始化進行了什麼規定?例如,如果空指針,浮點零和整數零都有不同的32位表示,那麼聲明'union {void * moe [1];浮動拉里[2]; unsigned char curly [12];} STOOGE = {0};''curly'的前四個字節顯然應該包含一個空指針的unsigned char'表示,但其餘的呢? – supercat 2013-03-04 17:25:36

+0

@supercat該標準在聯合和其他「聚合」類型之間沒有區別,參見C11 6.7.9/21。初始化規則遞歸地應用於所有成員。在你的例子中,第一個數組成員的第一項將顯式初始化爲一個空指針,然後剩下的所有項目就好像它們具有靜態存儲持續時間。也就是說,第一個數組的其餘部分,然後是所有其他數組成員。一切都將被設置爲零。 – Lundin 2013-03-05 07:24:10