作者purpose (purpose)
看板C_and_CPP
標題Re: [問題] try catch(...)的問題
時間Sat Oct 29 00:14:18 2011
: C++ 就不知怎處理 千奇百怪exception 所以想先找一個general的方式做catch
: 但連 divide by zero, null reference exception都catch不到好像也滿怪的
: 還是我用錯了?
就我所知的 x86 處理器狀況來回答。
Interrupt (中斷) 跟 Exception (例外) 這兩個名詞因為沒有公認的定義,
所以不同的書可能用不同解釋。
當中斷或例外發生時,程式的流程,總是會跳到不可知之地,
可以把它們當作在發生意外。
因為一件意外 (中斷/例外) 發生了,就必須處理掉這個意外,不能放著爛下去。
在最早的時候,處理的機制是使用「中斷向量表」(IVT)。
剛開機的時候,BIOS 把處理各類意外的函數,從自己的 ROM 複製到主記憶體去。
然後又到主記憶體物理位置為0的地方,填寫 256 組中斷向量,總共 1KB,
每組 4 Bytes,這就是在填寫「中斷向量表」。
若 CPU 發生第 N 號中斷,就選擇表格中對應的地方,轉移至處理中斷的程式碼。
到了保護模式出現後,CPU 多了些暫存器。
重要的是 IDTR,這個暫存器會指向主記憶體的某處,在該處會有一個新的表格
叫「中斷描述表」(IDT),此表取代了中斷向量表 (IVT)。
不過一樣還是只有 256 項。
當發生除以 0 例外時,因為這個例外的中斷編號為0:
在保護模式以前,會到物理記憶體位置0的地方,找出中斷處理程式的位置。
在保護模式以後,則是到 IDT 的第 0 項去查詢。
在安裝 Windows 跟 Linux 後,這些作業系統會依造自己喜好更改 IDT 的內容。
Windows 把所有的例外,不管原本是第幾號中斷,集中用同一個程式管理。
這個程式叫「Exception Dispatcher」。其主要是用一個叫「結構化例外處理」的機制。
有例外發生時,都是以執行緒為單位,每個執行緒裡有一份鍊結串列,這個鍊結
串列記載處理例外的函數指標,而串列的開頭由該執行緒當時的 FS 暫存器可找到。
所以 Exception Dispatcher 這程式 (Kernel Mode) 首先把發生例外的現場資訊
記下來,當到 Kernel 記憶體儲存,然後直接開你的那組鍊結串列,從開頭的例外處理
函數去跑。
當開頭的處理函數說「除以0」這個例外我不會處理,交給別人,那就會往下找,當
所有處理函數都說不會處理,那就會丟回給 Windows 回報程式執行錯誤,把你的程式
關閉。
而 C++ 的 try catch 區塊,就是安裝一個最新的例外處理函數進去 SEH 的串列,
只要 try 的區塊內有發生例外,都會交給你最新安裝的函數,看其 catch 怎麼寫。
如果 catch 只想要接香蕉,而 Exception Dispatcher 傳來的是芭樂,根本不想處理
也不想把例外丟給更上層的 try 那就騙 Exception Dispatcher 說已經處理完了,
繼續往下執行吧,那 SEH 之後的處理函數就不會繼續跑。
而 C++ 預設狀況下,根本不想安裝一個處理 "除以0" 例外的 Handler。
就直接丟給 Windows 去把程式終止就好。
那 C# 只是比較費功夫,把例外全部接收來,再細心分成很多種類,然後回報上去,
看你 Programmer 要不要寫程式去處理掉。
####
2011/10/29 AM 01:00 補充
前面的問題,我的新想法
C++ 是很多平台都有,他不可能管 Windows 是用 SEH 機制,管其 Exception Dispatcher
傳進來的例外資訊的格式為何。
就除以 0 例外來說,也許 C++ 不好確定告知這個例外情報時,OS 那邊會怎麼記載。
所以如果你真的很在乎除以0例外是否發生,自己在 try 裡面用 if 去判斷就好了。
甚至不要用 try catch 機制去處理,直接 if (除數==0) return 或 exit 都行。
而 C# 反正不管在什麼作業環境,他都比 C++ 多做一組 Handler,把所有發生的
例外都接收起來,然後進行判斷,再用統一的記錄格式去記載。
比如除以 0 例外一律用 "EH0" 記載,然後再 throw 出去,這時候因為除以 0 例外
經過一層處理,其格式固定了,所以就可以在 catch 那邊去捕抓到。
而 C++ 少了這一層 Handler,所以他處理例外的速度比較快,但是功能就比較少。
多數作業系統在「中斷/例外」發生時,應該都會判斷當時程式是否有連接 Debugger,
如果有連接 Debugger 就會告知說有例外發生了,並詢問是否要暫停程式
我們只要在這個時候,選擇暫停程式,再自己看當時暫存器、記憶體內容,
如果有原始碼資訊就直接原始碼,那就能夠判斷、捕抓所有的意外狀況。
當然像除以0例外,因為是 IDT 排第零項的例外,直接就會告知中斷編號為何了。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 124.8.128.187
推 tropical72: p 大太強了吧, 感覺都把 Windows Internal K 完了。 10/29 00:35
→ purpose:我也還沒看懂,主要想講一下理解,看有沒有哪裡還是錯的 10/29 00:39
→ purpose:等高手指正 10/29 00:39
※ 編輯: purpose 來自: 124.8.128.187 (10/29 01:14)
※ 編輯: purpose 來自: 124.8.128.187 (10/29 01:18)
推 tomap41017:只能推了 10/29 01:26
推 johnhmj:我也推,P大簡直就是高手高手高高手 10/29 01:42
推 tomnelson:概念脈絡非常清楚,推! 10/29 09:02
推 VictorTom:推:) 10/29 12:19
推 askaleroux:超神P 10/29 13:35