[讀書筆記] 關於Windows的結構化異常處理SEH(二)

上篇說的是終止處理程序,這篇接着看異常處理。

也就是:

<pre name="code" class="cpp">__try
{
	// 被保護的代碼
}
__except(exception filter/*異常過濾程序*/)
{
	// 異常處理程序
}


與終止處理程序不同,異常過濾程序與異常處理程序主要是操作系統負責執行的,另外,在try塊中的return,goto等語句不會導致像在終止處理程序中的那種局部展開,所以不會有額外的開銷,其實很好理解,異常過濾程序和異常處理程序只是在try塊發生異常才執行,而return之類的語句通常不會引發異常。

*異常過濾程序

如果try塊中的代碼出現被0的情況,CPU會捕獲這個時間,並拋出一個硬件異常(後面的文章會說到軟件異常),系統定位到except塊的開始處,這時,就會執行異常過濾程序,也就是對except括號中的表達式求值,這個表達式的值可能有3種:

EXCEPTION_EXECUTE_HANDLER: [except對操作系統說:我的{}中是異常處理程序,請執行,執行完畢後請跳到我的{}後面去接着執行後面的代碼]

  簡單來說就是相當於告訴系統,我知道這個異常,而且我也寫了處理這個異常的代碼,現在我要執行這些代碼。於是,系統執行全局展開,然後跳轉到異常處理程序中執行,在異常處理程序執行完畢後會接着執行except後面的代碼,就想異常沒有發生一樣,其實這個標記就意味着告訴系統,一切都在掌控中,有問題我自己有代碼會處理,請繼續運行就好了。

另:從Vista開始,如果一個異常發生在try/finally中,並在其上層沒有try/except塊(而且這個塊的過濾程序返回EXEPTION_EXCUTE_HANDLER),進程就會立刻終止,全局展開不會發生,當然finally塊也就不會被執行。

EXCEPTION_CONTINUE_EXECUTION:[except對操作系統說:我的{}中是異常處理程序,請執行,但是執行完畢後請跳回剛纔發生異常的語句重新從那裏執行]

這個標記的特點是,在except執行完畢後會調回異常發生的代碼重新執行一遍原來產生異常的代碼,這個特點就好像系統給你一個糾錯的權利,但是需要謹慎使用這個權利,通常正確的程序設計是在程序發生異常後要通知開發者,而不是用一些預定的代碼去試圖修復異常,這樣只會把問題隱藏起來,還有一個很重要的原因是,一句c++代碼可能被翻譯成很多條彙編指令,僅僅從產生異常的那句彙編指令重新執行往往不但不能修復異常,反而容易讓程序進入異常死循環。

EXCEPTION_EXCUTE_SEARCH:[except對操作系統說:我不處理異常,你去找我老大(外層的except)]

顧名思義,這個標記會通知系統讓系統在調用棧中向上查找前一個except塊的異常過濾程序並執行,而返回EXCEPTION_EXCUTE_SEARCH標記的except塊中的代碼永遠沒有機會執行。

決定返回什麼標記前,顯然要先知道是什麼類型的異常,這可以在異常過濾程序中調用GetExceptionCode來確定,此函數返回發生了哪類異常,當然此函數也只能在異常過濾程序中調用,也就是except後面的括號內。


上面說的異常都是指硬件異常,也就是由cpu捕獲事件而拋出的異常,我們也可以在應用程序代碼中主動拋出一個異常,也就是軟件異常,使用RaiseException函數(c++的throw應該最終也是調用的這個函數)


總結,這篇最關鍵的就是異常過濾程序返回的這三個標記,他們會導致系統的控制行爲不同。高級語言都有自己的異常處理體系,不過在windows上他們還是通過SEH實現的。


end.

第一遍讀這幾章,理解有誤處歡迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章