浅析C++编译器怎样实现异常处理问题

在介绍C++编译器如何实现异常处理的问题之前,先让大家了解下什么是C++编译器?其实C++编译器是一个与标准化C++高度兼容的编译环境,不同的编译器也会对不同的CPU进行不同的优化。

本文讨论了C++编译器如何实现异常处理。我将假定你已经熟悉异常处理的语法和机制,用于VC++的异常处理库,要用库中的处理程序替换掉VC++提供的那个,你只需要调用下面这个函数:

 
 
 
  1. install_my_handler();

之后,程序中的所有异常,从它们被抛出到堆栈展开(stack unwinding),再到调用catch块,***到程序恢复正常运行,都将由我的异常处理库来管理。

与其它C++特性一样,C++标准并没有规定编译器应该如何来实现异常处理。这意味着每一个编译器的提供商都可以用它们认为恰当的方式来实现它。下面我会 描述一下VC++是怎么做的,但即使你使用其它的编译器或操作系统①,本文也应该会是一篇很好的学习材料。VC++的实现方式是以windows系统的结 构化异常处理(SEH)②为基础的。

我认为C++编译器异常或者是被明确的抛出的,或者是由于除零溢出、空指针访问等引起的。当它发生时会产生一个中断,接下来控制权就会传递到操作系统 的手中。操作系统将调用异常处理程序,检查从异常发生位置开始的函数调用序列,进行堆栈展开和控制权转移。Windows定义了结构 "EXCEPTION_REGISTRATION",使我们能够向操作系统注册自己的异常处理程序。

 
 
 
  1. struct EXCEPTION_REGISTRATION
  2. {
  3.     EXCEPTION_REGISTRATION* prev;
  4.     DWORD handler;
  5. }; 

注册时,只需要创建这样一个结构,然后把它的地址放到FS段偏移0的位置上去就行了。下面这句汇编代码演示了这一操作:

 
 
 
  1. mov FS:[0], exc_regp

prev字段用于建立一个EXCEPTION_REGISTRATION结构的链表,每次注册新的EXCEPTION_REGISTRATION时,我们都要把原来注册的那个的地址存到prev中。那么,那个异常回调函数长什么样呢?在excpt.h中,windows定义了它的原形:

 
 
 
  1. EXCEPTION_DISPOSITION (*handler)( 
  2. _EXCEPTION_RECORD *ExcRecord, 
  3. void* EstablisherFrame, 
  4. _CONTEXT *ContextRecord, 
  5. void* DispatcherContext); 

不要管它的参数和返回值,我们先来看一个简单的例子。下面的程序注册了一个C++编译器异常处理程序,然后通过除以零产生了一个异常。异常处理程序捕获了它,打印了一条消息就完事大吉并退出了。

 
 
 
  1. #include 
  2. #include 
  3. using std::cout; 
  4. using std::endl; 
  5. struct EXCEPTION_REGISTRATION 
  6. EXCEPTION_REGISTRATION* prev; 
  7. DWORD handler; 
  8. }; 
  9. EXCEPTION_DISPOSITION myHandler( 
  10. _EXCEPTION_RECORD *ExcRecord, 
  11. void * EstablisherFrame, 
  12. _CONTEXT *ContextRecord, 
  13. void * DispatcherContext) 
  14. cout << "In the exception handler" << endl
  15. cout << "Just a demo. exiting..." << endl
  16. exit(0); 
  17. return ExceptionContinueExecution; //不会运行到这 
  18. int  g_div = 0; 
  19. void bar() 
  20. //初始化一个EXCEPTION_REGISTRATION结构 
  21. EXCEPTION_REGISTRATION reg, *preg = ®  
  22. reg.handler = (DWORD)myHandler; 
  23. //取得当前异常处理链的"头" 
  24. DWORD prev; 
  25. _asm 
  26. mov EAX, FS:[0] 
  27. mov prev, EAX 
  28. reg.prev = (EXCEPTION_REGISTRATION*) prev; 
  29. //注册! 
  30. _asm 
  31. mov EAX, preg 
  32. mov FS:[0], EAX 
  33. //产生一个异常 
  34. int  j = 10 / g_div;  //异常,除零溢出 
  35. int  main() 
  36. bar(); 
  37. return 0; 

注意EXCEPTION_REGISTRATION必须定义在栈上,并且必须位于比上一个结点更低的内存地址上,windows对此有严格要求,达不到的话,它就会立刻终止进程。

当前题目:浅析C++编译器怎样实现异常处理问题
文章出自:http://www.shufengxianlan.com/qtweb/news21/376071.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联