异常和异常处理(windows平台)

About Exceptions and Exception Handling

About Exception

当程序遇到一个异常或一个严重的错误时,通常意味着它不能继续正常运行并且需要停止执行。

例如,当遇到下列情况时,程序会出现异常:

  程序访问一个不可用的内存地址(例如,NULL指针);

无限递归导致的栈溢出;

向一个较小的缓冲区写入较大块的数据;

类的纯虚函数被调用;

申请内存失败(内存空间不足);

一个非法的参数被传递给C++函数;

C运行时库检测到一个错误并且需要程序终止执行。

 

有两种不同性质的异常:结构化异常(Structured Exception Handling, SEH)和类型化的C++异常。

SEH是为C语言设计的,但是他们也能够被用于C++SEH异常由__try{}__except(){}结构来处理。SEHVC++编译器特有的,因此如果你想要编写可移植的代码,就不应当使用SEH

C++中类型化的异常是由try{}catch(){}结构处理的。例如(例子来自这里http://www.cplusplus.com/doc/tutorial/exceptions/):

复制代码
 1 #include <iostream>
 2  using  namespace std;
 3  
 4  int main(){
 5      try{
 6         throw  20;
 7     }
 8      catch ( int e){
 9        cout <<  " An exception occrred. Exception Nr.  " << e << endl;
10     }
11  
12      return  0;
13 }
复制代码

 

结构化异常处理

当发生一个SEH异常时,你通常会看到一个意图向微软发送错误报告的弹出窗口。

你可以使用RaiseException()函数自己产生一个SEH异常。

你可以在你的代码中使用__try{}__except(Expression){}结构来捕获SEH异常。程序中的main()函数被这样的结构保护,因此默认地,所有未被处理的SEH异常都会被捕获。

例如:

复制代码
 1 #include <Windows.h>
 2  
 3  int main(){
 4      int *p = NULL;   //  pointer to NULL
 5      __try{
 6         //  Guarded code
 7         *p =  13;     //  causes an access violation exception;
 8      }
 9     __except(EXCEPTION_EXECUTE_HANDLER){   //  Here is exception filter expression
10          //  Here is exception handler
11          //  Terminate program
12         ExitProcess( 1);
13     }
14  
15      return  0;
16 }
复制代码

 

 

每一个SEH异常都有一个与其相关联的异常码(exception code)。你可以使用GetExceptionCode()函数来获取异常码。你可以通过GetExceptionInformation()来获取异常信息。为了使用这些函数,你通常会像下面示例中一样定制自己的exception filter

下面的例子说明了如何使用SEH exception filter

复制代码
 1  int seh_filter(unsigned  int code,  struct _EXCEPTION_POINTERS *ep){
 2      //  Generate error report
 3       //  Execute exception handler
 4       return EXCEPTION_EXECUTE_HANDLER;
 5 }
 6  
 7  int main(){
 8     __try{
 9         //  .. some buggy code here
10      }
11     __except(seh_filter(GetExceptionCode(), GetExceptionInformation())){
12         //  Terminate program
13         ExitProcess( 1);
14     }
15  
16      return  0;
17 }
复制代码

 

 

__try{}__exception(){}结构是面向C语言的,但是,你可以将一个SEH异常重定向到C++异常,并且你可以像处理C++异常一样处理它。我们可以使用C++运行时库中的_set_se_translator()函数来实现。

看一个MSDN中的例子(译者注:运行此例子需打开/EHa编译选项):

复制代码
 1 #include <cstdio>
 2 #include <windows.h>
 3 #include <eh.h>
 4  
 5  void SEFunc();
 6  void trans_func(unsigned  int, EXCEPTION_POINTERS *);
 7  
 8  class SE_Exception{
 9  private:
10     unsigned  int nSE;
11  public:
12     SE_Exception(){}
13     SE_Exception(unsigned  int n) : nSE(n){}
14     ~SE_Exception() {}
15     unsigned  int getSeNumber(){  return nSE; }
16 };
17  
18  int main( void){
19      try{
20        _set_se_translator(trans_func);
21        SEFunc();
22     }
23      catch(SE_Exception e){
24        printf( " Caught a __try exception with SE_Exception.\n ");
25     }
26 }
27  
28  void SEFunc(){
29     __try{
30         int x, y= 0;
31        x =  5 / y;
32     }
33     __finally{
34        printf( " In finally\n ");
35     }
36 }
37  
38  void trans_func(unsigned  int u, EXCEPTION_POINTERS* pExp){
39     printf( " In trans_func.\n ");
40      throw SE_Exception();
41 }

你可能忘记对一些潜在的错误代码使用__try{}__catch(Expression){}结构进行保护,而这些代码可能会产生异常,但是这个异常却没有被你的程序所处理。不用担心,这个未被处理的SEH异常能够被unhandled Exception filter所捕获,我们可以使用SetUnhandledExceptionFilter()函数设置top-levelunhandled exception filter

异常信息(异常发生时的CPU状态)通过EXCEPTION_POINTERS被传递给exception handler

例如:

 1   //  crt_settrans.cpp
 2   //  compile with: /EHa
 3   LONG WINAPI MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionPtrs){
 4       //  Do something, for example generate error report
 5        // ..%%%%%pc@ezCP]@jj^o^kMNCT\lDbcezpfZvW_qYGZqX[NhHdOtxORYzNKg\FQ?pmnuGXU]G>E>CMqGXut<J@<<R\m=fCsBXYz>gCoGL\X^e`Fuc`=K{XYCpGKp]fIUk_UPlHyWpDGNCY]_rfk^]fc\?HYTBi`XvGjMcF{RV`seiBUJ{d=k>MJYqquTFgmN_EHELKa`okprmMIFcbXraIxktSy<VmO>=H]dN`DgDrGJ@lAQZmWhNMpcgs<k_Cln=rE]BgNj^I]UKszsOXteyJGdJiqa_\`USA=GC^cez_e@YlnL^[rrjVuA[@KLpVeJ[aoeOEtJieEOUIYHbSpLtXiLuEexAiX]NhIklw`qixptEQcM{SG_L?BMYTxHZp`dqwfkN]iGijHxfP`XJzjePTYe@dnlfXXqRC[\tVKJEjxO^Z\mjx=taBIbACi`FNIuDRTlTOT_Tbl{{RTS{@lQjIuYATBEygeZOrrqwwiHs[CjOWHFdJt`RNQC_AVZbkjRj?HgDt@ljG=vSgDF_EfTmf@m_{qhuO_[NXnfUVq?ioq{ueWktpwP<pSHwlTQBPQpRS{{KCMaYqOJscwtNDuB<{gtKyZvv\elMo>KeL^hgKJfnsE[CueeW\bbBmvfRegMDWRBgLj{`MzB]pSo\wSpcAUHkuTPF_JDkipS[\?zj?km_xrnijBU<XQdhBYnn<hlaEoNbPuU>Ks[_j?ngWJfgPH{?[VVaDTHKOAuUrVDPu^paRpKX>ywgiRMLWyAFrPqHyvssBFhIHJv=h=KBPa\wTJCdz[oZAN`ih<G<wiLqt^VHCuMWGEINkaKov_sDibC^SvDXGdrlN[RTbdjNr?SSr?au\<<aqSOiq<[ltzGU_gczfXRTMdEtQfBimE@XI?^XjHOhPXD{STv{LPXWmrWKOVl=HU<aWDn??YBEjHiG`BmcEAWGBa`gfZzWlZ^rpf<^vijZAbUbPR=rQFlv^]XG@TkQnbcdMwIOlc{^bgc<{df?JZ?iytwfyx\gZuNEgaNI=d^DZlVthIB\IDXJJmoMCvXlQx{vTTMcS<dMqSGJptsx=`gKGcog[ZPOeM>TwJIdYXyOyP^Dmnzx=HvvK=WEIOPgaHNHKAr<UBGsj\SmP>gXANooPPcpsNuUmlIePmq^YVtvnurDE=>LlgxLR\^l^aYE?s?@nBlbA^[syvQA>oUx[{TQdWGiXeIeOOLKZ<Xt`Be>hA^k?<{iPAJDWx={dTJQH{Y?hCsFQdbT^dJeDePlLEYamPTOEUTbGiNRBzhhYSdhSkwcJI=yrJju>UAd@Ue=j<^rr>jQNNhEyz\XMI]zt%%%%%
 6        //  Execute default exception handler next
 7        return  EXCEPTION_EXECUTE_HANDLER;
 8  }
 9   
10   void  main(){
11      SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
12       //  .. some unsafe code here
13   }

向量化异常处理(Vectored Exception Handling

向量化异常处理(VEH)是结构化异常处理的一个扩展,它在Windows XP中被引入。

你可以使用AddVectoredExceptionHandler()函数添加一个向量化异常处理器,VEH的缺点是它只能用在WinXP及其以后的版本,因此需要在运行时检查AddVectoredExceptionHandler()函数是否存在。

要移除先前安装的异常处理器,可以使用RemoveVectoredExceptionHandler()函数。

VEH允许查看或处理应用程序中所有的异常。为了保持后向兼容,当程序中的某些部分发生SEH异常时,系统依次调用已安装的VEH处理器,直到它找到有用的SEH处理器。

VEH的一个优点是能够链接异常处理器(chain exception handlers),因此如果有人在你之前安装了向量化异常处理器,你仍然能截获这些异常。

当你需要像调试器一样监事所有的异常时,使用VEH是很合适的。问题是你需要决定哪个异常需要处理,哪个异常需要跳过。 In program's code, some exceptions may be intentionally guarded by __try{}__except(){} construction, and handling such exceptions in VEH and not passing it to frame-based SEH handler, you may introduce bugs into application logics.

VEH目前没有被CrashRpt所使用。SetUnhandledExceptionFilter()更加适用,因为它是top-level SEH处理器。如果没有人处理异常,top-level SEH处理器就会被调用,并且你不用决定是否要处理这个异常。

CRT 错误处理

除了SEH异常和C++类型化异常,C运行库(C runtime libraries, CRT)也提供它自己的错误处理机制,在你的程序中也应该考虑使用它。

CRT遇到一个未被处理的C++类型化异常时,它会调用terminate()函数。如果你想拦截这个调用并提供合适的行为,你应该使用set_terminate()函数设置错误处理器(error hanlder)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值