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

Visual C++ 結構化例外處理 (SEH) 深度解析:__try/__finally 與 __try/__except

     編輯:關於VC++

引言

結構化例外處理 (Structured Exception Handling, SEH) 是 Microsoft Visual C++ 提供的錯誤處理機制,與 C++ 標準的 try/catch/throw 不同,SEH 採用 __try/__finally (終止處理) 與 __try/__except (例外處理) 兩組關鍵字,允許將「主要邏輯」與「錯誤處理/資源清理」分離,提升程式碼可讀性與健壯性。

終止處理句柄 (__try/__finally)

語法與執行流程

__try {
    // Guarded body: 可能提前返回、跳轉、發生硬體例外
}
__finally {
    // Termination handler: 保證一定會執行
}

流程:執行 __try 區塊 → 无论正常結束、return、goto、longjmp 或硬體例外,__finally 區塊**必定執行** → 接著執行 __finally 之後的程式碼 (若無 return/goto 中斷)。

經典應用:訊號量釋放保證

DWORD Funcenstein2(void)
{
    DWORD dwTemp;
    __try {
        WaitForSingleObject(g_hSem, INFINITE);
        g_dwProtectedData = 5;
        dwTemp = g_dwProtectedData;
        return dwTemp; // 提前返回
    }
    __finally {
        ReleaseSemaphore(g_hSem, 1, NULL); // 保證釋放
    }
    // 此處程式碼不會執行
}

若無 __finally,提前 return 會導致訊號量永不釋放,造成死結。

局部展開 與 __leave

當 __try 區塊透過 return/goto/longjmp 離開時,編譯器會插入額外程式碼確保 __finally 執行,這稱為「局部展開」,會降低效能。使用 __leave 可避免局部展開:

__try {
    if (error) __leave; // 直接跳到 __finally,不產生局部展開開銷
    // 正常處理
}
__finally {
    // 清理
}

不執行 __finally 的情況

  • 呼叫 ExitThread、ExitProcess、abort 立即終止執行緒/進程。
  • 其他進程強制終止本進程。

例外處理句柄 (__try/__except)

語法

__try {
    // 可能發生硬體例外 (除以零、存取違規等)
}
__except (EXCEPTION_EXECUTE_HANDLER) {
    // 例外處理器
}

__except 後的運算式為例外篩選器,常用值:

  • EXCEPTION_EXECUTE_HANDLER (1):進入處理器。
  • EXCEPTION_CONTINUE_SEARCH (0):繼續尋找上層處理器。
  • EXCEPTION_CONTINUE_EXECUTION (-1):修復錯誤後繼續執行觸發指令。

實務範例:檔案讀取資源自動釋放

BOOL Funcarama1(void)
{
    HANDLE hFile = INVALID_HANDLE_VALUE;
    LPVOID lpBuf = NULL;
    __try {
        hFile = CreateFile(_T("SOMEDATA.DAT"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        if (hFile == INVALID_HANDLE_VALUE) __leave;
        lpBuf = VirtualAlloc(NULL, 1024, MEM_COMMIT, PAGE_READWRITE);
        if (!lpBuf) __leave;
        DWORD dwRead;
        if (!ReadFile(hFile, lpBuf, 1024, &dwRead, NULL) || dwRead == 0) __leave;
        // 資料處理...
    }
    __finally {
        if (lpBuf) VirtualFree(lpBuf, 0, MEM_RELEASE);
        if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
    }
    return TRUE;
}

對比傳統巢狀 if 錯誤檢查,SEH 版本邏輯線性、資源釋放集中、不易遺漏。

小測驗

DWORD FuncaDoodleDoo(void)
{
    DWORD dwTemp = 0;
    while (dwTemp < 10)
    {
        __try {
            if (dwTemp == 2) continue;
            if (dwTemp == 3) break;
        }
        __finally { dwTemp++; }
        dwTemp++;
    }
    dwTemp += 10;
    return dwTemp; // 答案:14
}

總結

SEH 提供了強大的資源管理與錯誤處理能力,特別適合系統層級程式設計。善用 __try/__finally 可確保清理程式碼必定執行;__try/__except 則能捕捉硬體例外。但需注意 ExitProcess 等會繞過 __finally,且濫用局部展開會影響效能,宜配合 __leave 最佳化。

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