try-except用法
try except是windows 系統專屬的異常處理模型,windows的異常處理模式,稱為SEH( structured exception handling ),
SEH的異常處理模型主要由try-except語句來完成,與標準的try catch相似。與C++異常處理模型使用catch關鍵字來定義異常處理模組,而SEH是採用__except關鍵
字來定義。並且,catch關鍵字後面往往好像接受一個函數參數一樣,可以是各種類型的異常資料對象;但是__except關鍵字則不同,它後面跟的卻是一個運算式.
我們知道,函數調用也是一個運算式。
我們來看下面這個例子,這個例子是用來處理棧溢出的異常。
long WINAPI FilterFunc(DWORD dwExceptionCode)
{
return (dwExceptionCode == STATUS_STACK_OVERFLOW) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
}
UINT WINAPI ThreadFunc(LPVOID param)
{
__try
{
// guarded code
}
__except (FilterFunc(GetExceptionCode()))
{
// 如果是棧溢出,進行處理。
}
return TRUEt;
}
except參數的值有以下三種:
EXCEPTION_CONTINUE_EXECUTION (–1) 異常被忽略,控制流程將在異常出現的點之後,繼續恢複運行。
EXCEPTION_CONTINUE_SEARCH (0) 異常不被識別,也即當前的這個__except模組不是這個異常錯誤所對應的正確的異常處理模組。系統將繼續到上一try-
except域中繼續尋找一個恰當的__except模組。
EXCEPTION_EXECUTE_HANDLER (1) 異常已經被識別,控制流程將進入到__except模組中運行異常處理代碼
try-except的關鍵是如何在__except模組中獲得異常錯誤的相關資訊.
Windows提供了兩個API函數來擷取異常資訊:
LPEXCEPTION_POINTERS GetExceptionInformation(VOID); //取得異常相關資訊
DWORD GetExceptionCode(VOID); // 取得異常編號
GetExceptionCode()返回異常編號,而GetExceptionInformation()返回更豐富的資訊,EXCEPTION_POINTERS結構如下,
typedef struct _EXCEPTION_POINTERS { // exp
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS;
其中EXCEPTION_RECORD類型,它記錄了一些與異常相關的資訊;而CONTEXT資料結構體中記錄了異常發生時,線程當時的上下文環境,主要包括寄存器的值。
有了這些資訊,__except模組便可以對異常錯誤進行很好的分類和恢複處理,通常我們需要一個過濾函數來輔助。一般稱為是filterfunction.過濾函數只過濾需要處
理的異常。
int exception_access_violation_filter(LPEXCEPTION_POINTERS p_exinfo)
{
if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
messagebox("access vialation exceptionn");
return EXCEPTION_EXECUTE_HANDLER ; //告訴except處理這個異常
}
else return EXCEPTION_CONTINUE_SEARCH; //不告訴except處理這個異常
}
int exception_int_divide_by_zero_filter(LPEXCEPTION_POINTERS p_exinfo)
{
if(p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
{
return EXCEPTION_EXECUTE_HANDLER; //告訴except處理這個異常
}
else return EXCEPTION_CONTINUE_SEARCH; //不告訴except處理這個異常
}
於是,你可以這樣寫這段異常處理代碼:
__try
{
// guarded code
}
__except(exception_access_violation_filter(GetExceptionInformation()))
{
//
}
__try
{
// guarded code
}
__exceptexception_int_divide_by_zero_filter(GetExceptionInformation()))
{
//exception handling
}
SEH異常處理模型中,也可以拋出一個異常。對應的WindowsAPI函數是RaiseException,
VOID RaiseException(
DWORD dwExceptionCode, // 異常的編號
DWORD dwExceptionFlags, // 異常標記
DWORD nNumberOfArguments, // 參數個數
CONST DWORD *lpArguments // 參數數組首地址
);
通常,後三個參數基本不用
SEH異常處理還有try-finally.類似於java裡的try-catch-finally.但是SEH的try只能和except和finally兩者之間的一個搭配,不能有try-except-finnaly.
C++異常模型用try-catch文法定義,而SEH異常模型則用try-except文法,與C++異常模型相似,try-except也支援多層的try-except嵌套。
try-except模型中,一個try塊只能是有一個except塊;而C++異常模型中,一個try塊可以有多個catch塊。
C++異常模型是按照異常對象的類型來進行匹配尋找的;而try-except模型則不同,它通過一個運算式的值來進行判斷.
__except關鍵字後面跟的運算式,它可以是各種類型的運算式,例如,它可以是一個函數調用,或是一個條件運算式,或是一個逗號運算式,或乾脆就是一個整
型常量等等。最常用的是一個函數運算式,並且通過利用GetExceptionCode()或GetExceptionInformation ()函數來擷取當前的異常錯誤資訊,便於程式員有效控制異常
錯誤的分類處理。
SEH異常處理模型中,異常通過RaiseException()函數拋出。RaiseException()函數的作用類似於C++異常模型中的throw。
關於SEH異常處理更詳細的資料,你可以去看windows via c/c++這本書,中文譯名是windows核心編程。不過還是建議你看英文原版,翻譯的版本品質不高。