看板 C_and_CPP 關於我們 聯絡資訊
: 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