2008-11-19 97 views
2

任何人都可以向我解釋這是什麼意思?C++ Visual Studio運行時錯誤

「運行時檢查失敗#0 - ESP的值在函數調用中沒有正確保存,這通常是調用一個調用約定的函數聲明的結果,其中函數指針聲明的調用約定不同「。

+0

你可以添加一些代碼嗎? – 2008-11-19 11:49:29

回答

7

當調用一個函數時,編譯器必須在棧上推入一些參數,或者將它們放入一些寄存器中。函數體將改變一些內存位置(或寄存器)以包含返回值。然後它將返回到堆棧上「某處」存儲位置的代碼塊。

調用約定指定具體的細節:例如首先按下返回地址,然後從左向右推棧上的參數(輸入或輸出),然後執行該函數,再次關閉參數,然後彈出返回地址並跳轉到該位置。

如果調用者執行的操作與函數所期望的不同,則可能出錯(返回位置不在預期的堆棧位置)。

ESP通常是包含當前堆棧幀地址的寄存器。該寄存器與索引結合使用以獲取函數體中的參數。當返回時,堆頂通常重置爲ESP,並且處理器跳到例如ESP + 1。

事情,可能會導致這種情況發生:

  • 有人寫在堆棧的值,改變了返回地點(如緩衝區溢出)
  • 來電有比被叫
  • 不同的調用約定
+0

最後一個原因不完全正確,它應該是:'被調用者與調用者的假定有不同的調用約定'。 – 2008-11-19 13:34:09

3

可能性#1是你的對象得到了別名錯誤。這意味着編譯器錯誤地錯誤地鑄造了一個對象,通常是最優化的。

可能性#2您使用對無效對象的引用。

可能性#3一些完全不相關的東西破壞了堆棧,可能是緩衝區溢出。

沒有代碼示例除了這些可能性之外很難預測,但它們覆蓋了可能發生的事情的90%。

1

這意味着處理器ESP寄存器中的值在調用函數後沒有正確恢復。

由於已經說過的函數參數被壓入堆棧,並且在函數結束後通過調整esp寄存器來轉儲。在某些調用約定中,esp寄存器在調用代碼返回函數調用後進行調整。在其他約定中,它在被返回之前被調用的函數調整。

當調用esp出現在調用代碼和被調用代碼之間時出現分歧時,我看到了這個錯誤。仔細看看函數是如何聲明的,特別是如果它在一個單獨的庫或DLL中。

0

這是通常的情況下鑄造時的函數指針閉嘴編譯器調用一個Windows API時,如對話框:

Windows是所有函數有點奇怪與STDCALL被定義調用約定,違背了CDECL,C中的默認爲此應傳遞到Windows API的所有功能應與WINAPI定義(一個定義STDCALL):

INT_PTR WINAPI dlgProc(HWND, UINT, WPARAM, LPARAM); 

如果你錯過,而是定義你的dlgProc爲:

INT_PTR dlgProc(HWND, UINT, WPARAM, LPARAM); 

您的代碼將無法編譯,你可能會受到嚴峻的誘惑,只是關上了frikkin編譯器提供了:

DialogBox(hInstance, MAKEINTRESOURCE(MY_DIALOG), hWnd, (DLGPROC)&dlgProc); // be a DLGPROC already, dammit!! 

不要那樣做。該程序將崩潰。編譯器是你的朋友。 C風格的演員並非如此。編譯器試圖告訴你,這將發生。這是對的。聽這個。