[英]Why does stack overflow throw no error in Visual C++?
在Microsoft Visual C ++ 2010中,我創建了一個程序,該程序可能會導致堆棧溢出。 當我使用“開始調試”運行程序時,發生堆棧溢出時會引發錯誤。 當我使用“start without debugging”運行它時,不會拋出任何錯誤,程序只是靜默終止,就像它已成功完成一樣。 有人可以向我解釋發生了什么事嗎? 還有其他任何編譯器不會在堆棧溢出時拋出錯誤嗎?
(我認為這是提出有關堆棧溢出的問題的正確位置。)
C ++不會像托管環境那樣牽着你的手。 堆棧溢出意味着未定義的行為。
堆棧溢出是未定義的行為。 編譯器完全有權忽略它或導致任何事件發生。
因為當進程堆棧溢出時,它不再是一個有效的進程。 顯示錯誤消息需要堆棧。
至於為什么調試器能夠拋出這樣的異常,在這種情況下,進程被保留,因為它以調試模式附加到調試器的進程。 您的進程沒有顯示錯誤,調試器是。
在Windows機器上,您可以捕獲與堆棧溢出相對應的SEH異常。 例如,您可以看到boost :: regex的源代碼(Google for BOOST_REGEX_HAS_MS_STACK_GUARD)。
很可能是編譯器優化了預期的堆棧溢出。 請考慮以下偽代碼示例:
void RecursiveMethod(int n)
{
if (n % 1024 == 0)
print n;
// call recursively
RecursiveMethod(n + 1);
}
該方法將遞歸調用自身並快速溢出堆棧,因為沒有退出條件。
但是,大多數編譯器都使用尾遞歸 ,這種技術將遞歸函數調用轉換為循環結構。
應該注意的是,對於尾遞歸,上面的程序將在無限循環中運行而不是靜默退出。
Bart de Smet有一篇很好的博客文章,解釋了這種技術在.NET中是如何工作的:
在調試模式下,您需要開銷。 您希望它檢測您是否損壞了堆棧,溢出了緩沖區等。此開銷內置於調試工具和調試器中。 在高級術語中,調試工具是額外的代碼和數據,放在那里以幫助標記錯誤,調試器可以檢測標記的錯誤並通知用戶(當然除了幫助您調試)。
如果您正在運行在發布模式下編譯的項目,或者沒有附加調試器,那么當程序死亡時,沒有人可以聽到程序的尖叫:)如果一棵樹落在森林里......
根據您的編程方式,C ++在沒有訓練輪的情況下進行編程。 如果你撞牆,沒有人會在那里告訴你,你搞砸了。 你將崩潰和燃燒,甚至更糟糕的是,崩潰並繼續在一個非常殘廢的狀態下運行,而不知道什么是錯的。 因此,它可以非常快。 沒有額外的檢查或安全防護措施,以防止它在處理程序的全部速度和潛力(即,您編入程序的多少額外步驟)中超越程序。
在調試版本中,會進行大量的堆棧檢查以幫助您檢測堆棧溢出,堆棧損壞等問題。它們不會出現在發布版本中,因為它們會影響應用程序的性能。 正如其他人所指出的,堆棧溢出是未定義的行為,因此編譯器根本不需要實現這樣的堆棧檢查。
當您處於調試環境中時,運行時檢查將幫助您檢測發布版本中也會出現的問題,因此,如果您修復了調試版本中檢測到的所有問題,那么它們也應該在發布版本中修復。 。 。 理論上。 實際上,有時您在調試版本中看到的錯誤在您的發布版本中不存在,反之亦然。
堆棧溢出不應該發生。 通常,堆棧溢出僅通過無意的遞歸函數調用或通過在堆棧上分配足夠大的緩沖區而發生。 前者顯然是一個bug,而后者應該使用堆。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.