<b>C++编译器若何实现非常处理</b>[VC/C++编程]
本文“<b>C++编译器若何实现非常处理</b>[VC/C++编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
译者注:本文在网上已经有几个译本,但都不完好,所以我决意自己把它翻译过来.固然力求信、雅、达,但鉴于这是我的第一次翻译阅历,不足之处敬请谅解并指出.
与传统语言相比,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
mov FS:[0], EAX
}
//产生一个非常
int j = 10 / g_div; //非常,除零溢出
}
int main()
{
bar();
return 0;
}
/*-------输出-------------------
In the exception handler
Just a demo. exiting...
---------------------------------*/
注意EXCEPTION_REGISTRATION必须定义在栈上,并且必须位于比上一个结点更低的内存地址上,Windows对此有严峻要求,达不到的话,它就会立即终止进程.
函数和仓库
仓库是用来保存部分对象的持续内存区.更明确的说,每个函数都有一个相关的栈桢(stack frame)来保存它全部的部分对象和表达式计算历程顶用到的暂时对象,至少理论上是这样的.但实际中,编译器常常会把一些对象放到存放器中以便能以更快的速度拜候.仓库是一个处理器(CPU)层次的概念,为了操作它,处理器供应了一些专用的存放器和指令.
图1是一个典型的仓库,它示出了函数foo调用bar,bar又调用widget时的情形.请注意仓库是向下增长的,这意味着新压入的项的地址低于原有项的地址.
以上是“<b>C++编译器若何实现非常处理</b>[VC/C++编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |