2017-07-16 42 views
-1
typedef struct 
{ 
    int a[2]; 
    double d; 
}struct_t; 

double fun(int i) 
{ 
    volatile struct_t s; 
    s.d = 3.14; 
    s.a[i] = 1073741824; 
    return s.d; 
} 

enter image description here存儲器引用錯誤例

我遇到了這個例子,同時瞭解CSAPP過程。解釋如下所示。但我仍然無法弄清楚。 enter image description here

+0

在本例中考慮int的sizeof,double的sizeof以及保證可寫的內存。 –

+2

你真正的問題是什麼?你不明白什麼? –

+0

'double fun(int i){if(i < 0 || i > 1){.. handle error ..} ...}'? –

回答

2

我相信(告訴我,如果我錯了),因爲結構被存儲爲一件大事,引用超出範圍的數組索引將調出結構中下一個元素的數據。

在內存中,有一個int,另一個int,然後是一個double。它們全都相鄰存放。

讓我們舉個簡單的例子:

typedef struct { 
    int X[2]; 
    int Y; 
} struct_t; 

如果我們訪問元素#3(X [2])的struct的,我們會得到Y,就像這樣:

void main() { 
    volatile struct_t s; 
    s.X[0] = 99; 
    s.X[1] = 98; 
    s.Y = 97; 
    printf("%i", s.X[2]); 
} 

該輸出97,因爲struct_t的第三個int大小的塊是97.

現在讓我們看看你的問題。 struct_t的前四個字節屬於int數組。最後八個屬於雙。 fun()將最後八個設置爲3.14,根據我的編譯器,它等於0x51EB851F。然後它將A的第I個字節設置爲0x4000。因此,通過寫入「第三個」數組元素(與double重疊)。這將覆蓋double,並改變它的值。

通過寫入第6個字節,您開始寫出內存不足,這給您段錯誤。不過,GCC有另一個怪癖。 CPU可以更快地訪問偶數地址上對齊的數據,因此GCC會將填充插入到結構中。另外,intdouble的大小也會隨着系統的不同而變化,這使得本例在不同的系統上輸出不同的東西。

+0

從會計觀點來看,您沒有關閉,而是從您調用的C標準觀點*未定義行爲*嘗試訪問定義範圍之外的數組元素。 –

+0

這是真的。 CSAPP課程正在訪問一個超出界限的數組來展示一個觀點,並且可能不是旨在鼓勵導致未定義行爲的代碼(至少,我希望如此)。 –

+1

未定義的行爲通常在stackoverflow中被忽視。我認爲這有點失控,這是一個完全教育的例子,只要你添加免責聲明,不同的系統可能會表現出不同的行爲,並且解釋顯示在特定情況下發生了什麼 – Leeor