快速业务通道

C++编译器如何实现异常处理

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-30

译者注:本文在网上已经有几个译本,但都不完整,所以我决定自己把它翻译过来。虽然力求信、雅、达,但鉴于这是我的第一次翻译经历,不足之处敬请谅解并指出。

与传统语言相比,C++的一项革命性创新就是它支持异常处理。传统的错误处理方式经常满足不了要求,而异常处理则是一个极好的替代解决方案。它将正常代码和错误处理代码清晰的划分开来,程序变得非常干净并且容易维护。本文讨论了编译器如何实现异常处理。我将假定你已经熟悉异常处理的语法和机制。本文还提供了一个用于VC++的异常处理库,要用库中的处理程序替换掉VC++提供的那个,你只需要调用下面这个函数:
install_my_handler();

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

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

结构化异常处理—概述

在本文的讨论中,我认为异常或者是被明确的抛出的,或者是由于除零溢出、空指针访问等引起的。当它发生时会产生一个中断,接下来控制权就会传递到操作系统的手中。操作系统将调用异常处理程序,检查从异常发生位置开始的函数调用序列,进行堆栈展开和控制权转移。Windows定义了结构“EXCEPTION_REGISTRATION”,使我们能够向操作系统注册自己的异常处理程序。
struct EXCEPTION_REGISTRATION
{
  EXCEPTION_REGISTRATION* prev;
  DWORD handler;
};
  注册时,只需要创建这样一个结构,然后把它的地址放到FS段偏移0的位置上去就行了。下面这句汇编代码演示了这一操作:

mov FS:[0], exc_regp
  prev字段用于建立一个EXCEPTION_REGISTRATION结构的链表,每次注册新的EXCEPTION_REGISTRATION时,我们都要把原来注册的那个的地址存到prev中。

那么,那个异常回调函数长什么样呢?在excpt.h中,windows定义了它的原形:

EXCEPTION_DISPOSITION (*handler)(
  _EXCEPTION_RECORD *ExcRecord,
  void* EstablisherFrame,
  _CONTEXT *ContextRecord,
  void* DispatcherContext); 
  不要管它的参数和返回值,我们先来看一个简单的例子。下面的程序注册了一个异常处理程序,然后通过除以零产生了一个异常。异常处理程序捕获了它,打印了一条消息就完事大吉并退出了。

#include <iostream>
#include <windows.h>
using std::cout;
using std::endl;
struct EXCEPTION_REGISTRATION
{
  EXCEPTION_REGISTRATION* prev;
  DWORD handler;
};
EXCEPTION_DISPOSITION myHandler(
  _EXCEPTION_RECORD *ExcRecord,
  void * EstablisherFrame,
  _CONTEXT *ContextRecord,
  void * DispatcherContext)
{
  cout << "In the exception handler" << endl;
  cout << "Just a demo. exiting..." << endl;
  exit(0);
  return ExceptionContinueExecution; //不会运行到这
}
int g_div = 0;
void bar()
{
  //初始化一个EXCEPTION_REGISTRATION结构
  EXCEPTION_REGISTRATION reg, *preg = ® 
  reg.handler = (DWORD)myHandler;
  //取得当前异常处理链的“头”
  DWORD prev;
  _asm
  {
    mov EAX, FS:[0]
    mov prev, EAX
  }
  reg.prev = (EXCEPTION_REGISTRATION*) prev;
  //注册!
  _asm
  {
    mov EAX, preg
    mo

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号