2009-10-15 57 views
4

我想知道爲什麼訪問衝突的cout和堆棧溢出在下面的兩段代碼爲發生的printf訪問衝突。爲什麼對cout和堆棧溢出的printf的

我想知道爲什麼訪問衝突的第一個代碼而不是堆棧溢出。

首先代碼,我得到的訪問衝突:

void Test(); 

void Test() 
{ 
    static int i = 0; 
     cout << i++ << endl;  
    Test(); 
} 
int main() 
{ 

    Test(); 

    return 0; 
} 

二代碼,我得到堆棧溢出:

void Test(); 

void Test() 
{ 
    static int i = 0; 
     printf("%d\n", i++);  
    Test(); 
} 
int main() 
{ 

    Test(); 

    return 0; 
} 

答案將得到高度讚賞。

在此先感謝

+1

是否包含了正確的頭文件? – Toad 2009-10-15 07:19:20

+10

嗯...你問爲什麼第一個例子給出了一個訪問衝突而不是堆棧溢出,作爲迴應,大家都在告訴你爲什麼第二個例子會導致堆棧溢出。有趣的是,每個人都回答他們知道答案的問題,而不是你實際問到的問題。 – 2009-10-15 07:26:06

+0

同意保羅。 – 2009-10-15 07:30:28

回答

18

我想你明白,這兩種功能的碰撞,由於堆耗盡在無限遞歸的嘗試之後。我想你問的是:爲什麼cout示例不會與「堆棧溢出」崩潰?

我不認爲答案與編譯器的檢測尾遞歸做。如果編譯器優化了遞歸,那麼這兩個示例都不會崩潰。

我猜測發生了什麼事。在某些情況下(例如Windows),在堆棧末尾分配一個虛擬內存「保護頁」時會實現「堆棧溢出」異常。當堆棧訪問命中此防護頁時,會生成一個特殊的異常類型。

由於英特爾的小粒度頁長爲4096個字節,保護頁守衛在一定範圍內的內存大小。如果一個函數調用分配超過4096字節的局部變量,那麼從它的第一個堆棧訪問實際上可能會延伸超出的保護頁面。下一頁可以預期是無保留的內存,所以在這種情況下訪問衝突是有意義的。

當然,你沒有在你的例子中明確聲明任何局部變量。我會假設其中一個運算符<(<)()方法分配多於一頁局部變量。換句話說,訪問衝突發生在運算符< <()方法或cout實現的一些其他部分(臨時對象構造函數等)的開始處附近。

此外,即使在您編寫的函數中,運算符< <()實現將需要爲中間結果創建一些存儲。該存儲可能被編譯器分配爲本地存儲。不過,我懷疑在你的例子中會增加4k。

真正理解的唯一方法是查看訪問衝突的堆棧跟蹤,以查看觸發它的指令。

獲得訪問衝突的堆棧跟蹤以及錯誤操作碼區域周圍的反彙編?

如果您使用的是微軟的C編譯器,另一種可能是printf()和自己的函數進行編譯/ Ge和運營商< <()沒有,或者只有你的函數用/ Ge和因素編譯類似於上面描述的那些巧合導致您看到的行爲 - 因爲在printf()示例中,崩潰發生在函數被調用時以及在調用庫時的運算符中。

+0

@Heath,「爲什麼cout示例不會與」Stack Overflow「一起崩潰?」 :是:)。夢幻般的答案 – mahesh 2009-10-15 08:46:34

+0

謝謝mahesh。請注意,如果您正在使用Microsoft的/ Ge開關,則會應用類似的解釋,正如我在上面添加的那樣。 – 2009-10-15 08:58:41

+0

Heath,Yeha ...非常感謝:)。 – mahesh 2009-10-15 09:42:50

4

兩個遞歸函數將永遠不會停止。 看來,在第二種情況下,編譯器沒有執行尾部優化,因此堆棧溢出。

1

無限遞歸調用用於堆棧溢出。至於訪問衝突......它實際上取決於STL流的實現。您需要承擔流的源代碼來看看,找出...

0

儘管大多數人誤解了你的問題,但答案就在那裏。

第二個示例以堆棧溢出結束,因爲每個函數調用都將一個幀推入堆棧。最終,它變得太大了。我同意CătălinPitiş的觀點,很難知道爲什麼流示例以訪問衝突結束而沒有查看源代碼。

+1

這個答案和CătălinPitiş的答案有什麼不同嗎? – SadSido 2009-10-15 07:38:35

2

這兩個函數都會在我的機器上觸發堆棧溢出。我正在編譯它與MS Visual Studio 2005.也許你應該指定你的平臺&編譯器,這將有助於調查...

也許你在調試模式下編譯的東西,你的「cout」實現包括一些檢查,即由於堆棧損壞而無法執行?也許你的編譯器生成的代碼,試圖從堆棧溢出恢復並彈出一個無效的返回地址?也許你正在移動設備上運行它?很難說不知道平臺和編譯器。

0

這個記得我疊的問題被損壞,調試器不要再追失敗的程序崩潰