首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

C++ 編譯器如何實現異常處理:基於 Windows SEH 的深度解析

     編輯:VC 教學

前言

C++ 的異常處理機制是相對傳統錯誤處理的一大創新,它將正常邏輯與錯誤處理清晰分離,使程式碼更整潔、易維護。本文探討編譯器如何實現異常處理,假設讀者已熟悉異常語法。文中亦提供一個自定義的 VC++ 異常處理庫,調用 install_my_handler() 即可替換預設處理器,接管從拋出、堆疊展開到 catch 區塊的完整流程。

編譯器實現的多樣性

C++ 標準未規定編譯器必須如何實現異常處理,各廠商可自行設計。本文以 Visual C++ 為例,其實現基於 Windows 結構化異常處理(SEH)。即使使用其他編譯器或作業系統,本文仍具參考價值。

Windows SEH 概覽

異常可能由明確拋出或硬體錯誤(除零、空指標)觸發,產生中斷,控制權移交作業系統。OS 調用異常處理器,檢查呼叫鏈,執行堆疊展開與控制轉移。Windows 定義 EXCEPTION_REGISTRATION 結構供註冊自定義處理器:

struct EXCEPTION_REGISTRATION {
    EXCEPTION_REGISTRATION* prev;
    DWORD handler;
};

註冊時,建立此結構並將其位址寫入 FS:[0]。prev 欄位串聯舊的註冊記錄,形成鏈表。異常回調函數原型定義於 excpt.h:

EXCEPTION_DISPOSITION (*handler)(
    _EXCEPTION_RECORD *ExcRecord,
    void* EstablisherFrame,
    _CONTEXT *ContextRecord,
    void* DispatcherContext);

簡易 SEH 示例

下列程式註冊處理器,製造除零異常,處理器捕獲後列印訊息並退出:

#include <iostream>
#include <windows.h>
using std::cout; using std::endl;

struct EXCEPTION_REGISTRATION { EXCEPTION_REGISTRATION* prev; DWORD handler; };

EXCEPTION_DISPOSITION myHandler(_EXCEPTION_RECORD*, void*, _CONTEXT*, void*) {
    cout << "In the exception handler" << endl;
    cout << "Just a demo. exiting..." << endl;
    exit(0);
    return ExceptionContinueExecution;
}

int g_p = 0;
void bar() {
    EXCEPTION_REGISTRATION reg, *preg = &reg;
    reg.handler = (DWORD)myHandler;
    DWORD prev;
    _asm { mov EAX, FS:[0]; mov prev, EAX }
    reg.prev = (EXCEPTION_REGISTRATION*)prev;
    _asm { mov EAX, preg; mov FS:[0], EAX }
    int j = 10 / g_p; // 觸發除零異常
}
int main() { bar(); return 0; }

輸出: In the exception handler / Just a demo. exiting...

注意:EXCEPTION_REGISTRATION 必須分配在堆疊上,且位址低於前一節點,否則 Windows 會終止進程。

函數與堆疊

堆疊保存區域物件,每個函數擁有堆疊幀。編譯器常將熱門物件放入暫存器優化存取。堆疊向下增長(新項目位址較低)。下圖展示 foo → bar → widget 呼叫時的堆疊佈局:

理解堆疊結構是掌握異常處理中堆疊展開機制的基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved