`
kzn535kz
  • 浏览: 14314 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

结构化异常处理

 
阅读更多

结构化异常处理
2010年07月30日
  结构化异常处理( S E H)
  S E H实际包含两个主要功能:结束处理( termination handling)和异常处理( e x c e p t i o nh a n d l i n g)。本章讨论结束处理,下一章讨论异常处理。
  一个结束处理程序能够确保去调用和执行一个代码块(结束处理程序,termination handler),而不管另外一段代码(保护体, guarded body)是如何退出的。结束处理程序的文法结构(使用微软的Visual C++编译程序)如下: __try和__finally关键字用来标出结束处理程序两段代码的轮廓。在上面的代码段中,操作系统和编译程序共同来确保结束处理程序中的- - f i n a l l y代码块能够被执行,不管保护体( t r y块)是如何退出的。不论你在保护体中使用r e t u r n,还是g o t o,或者是l o n g j u m p,结束处理程序(f i n a l l y块)都将被调用。下面将通过几个例子来说明这一点。
  通过使用结束处理程序,可以避免r e t u r n语句的过早执行。当r e t u r n语句试图退出t r y块时,编译程序要确保f i n a l l y块中的代码首先被执行。要保证f i n a l l y块中的代码在t r y块中的r e t u r n语句退出之前执行。
  23.12 关于finally块的说明
  
我们已经明确区分了强制执行f i n a l l y块的两种情况:
  从t r y块进入f i n a l l y块的正常控制流。
  局部展开:从t r y块的过早退出(g o t o、l o n g j u m p、c o n t i n u e、b r e a k、r e t u r n等)强制控制转移到f i n a l l y块。
  第三种情况,全局展开( global unwind),在发生的时候没有明显的标识,我们在本章前面F u n c f u r t e r 1函数中已经见到。在F u n c f u r t e r 1的t r y块中,有一个对F u n c i n a t o r函数的调用。如果F u n c i n a t o r函数引起一个内存访问违规( memory access violation ),一个全局展开会使F u n c f u r t e r 1的f i n a l l y块执行。下一章将详细讨论全局展开。
  由于以上三种情况中某一种的结果而导致f i n a l l y块中的代码开始执行。为了确定是哪一种情况引起f i n a l l y块执行,可以调用内部函数(或内蕴函数,intrinsic function)Abnormal Te r m i n a t i o n: 这个内部函数只在f i n a l l y块中调用,返回一个B o o l e a n值。指出与f i n a l l y块相结合的t r y块是否过早退出。换句话说,如果控制流离开t r y块并自然进入f i n a l l y块,A b n o r m a l Te r m i n a t i o n将返回FA L S E。如果控制流非正常退出t r y块―通常由于g o t o、r e t u r n、b r e a k或c o n t i n u e语句引起的局部展开,或由于内存访问违规或其他异常引起的全局展开―对A b n o r m a l Te r m i n a t i o n的调用将返回T R U E。没有办法区别f i n a l l y块的执行是由于全局展开还是由于局部展开。但这通常不会成为问题,因为可以避免编写执行局部展开的代码。
  注意内部函数是编译程序识别的一种特殊函数。编译程序为内部函数产生内联(i n l i n e)代码而不是生成调用函数的代码。例如, m e m c p y是一个内部函数(如果指定/ O i编译程序开关)。当编译程序看到一个对m e m c p y的调用,它直接将m e m c p y的代码插入调用m e m c p y的函数中,而不是生成一个对m e m c p y函数的调用。其作用是代码的长度增加了,但执行速度加快了。 异常是我们不希望有的事件。在编写程序的时候,程序员不会想去存取一个无效的内存地址或用0来除一个数值。不过,这样的错误还是常常会发生的。C P U负责捕捉无效内存访问和用0除一个数值这种错误,并相应引发一个异常作为对这些错误的反应。C P U引发的异常,就是所谓的硬件异常( hardware exception)。在本章的后面,我们还会看到操作系统和应用程序也可以引发相应的异常,称为软件异常( software exception)
  当出现一个硬件或软件异常时,操作系统向应用程序提供机会来考察是什么类型的异常被引发,并能够让应用程序自己来处理异常。下面就是异常处理程序的文法: 注意__e x c e p t关键字。每当你建立一个t r y块,它必须跟随一个f i n a l l y块或一个e x c e p t块。一个try 块之后不能既有f i n a l l y块又有e x c e p t块。但可以在t r y - e x c e p t块中嵌套t r y - f i n a l l y块,反过来也可以。
  异常过滤器( exception filter)和异常处理程序是通过操作系统直接执行的,编译程序在计算异常过滤器表达式和执行异常处理程序方面不做什么事。下面几节的内容举例说明t r y - e x c e p t块的正常执行,解释操作系统如何以及为什么计算异常过滤器,并给出操作系统执行异常处理程序中代码的环境。 表24-1 标识符及其定义  24.2 EXCEPTION_EXECUTE_HANDLER 在F u n c m e i s t e r 2中,异常过滤器表达式的值是E X C E P T I O N _ E X E C U T E _ H A N D L E R。这个值的意思是要告诉系统:“我认出了这个异常。即,我感觉这个异常可能在某个时候发生,我已编写了代码来处理这个问题,现在我想执行这个代码。”在这个时候,系统执行一个全局展开(本章后面将讨论),然后执行向e x c e p t块中代码(异常处理程序代码)的跳转。在e x c e p t块中代码执行完之后,系统考虑这个要被处理的异常并允许应用程序继续执行。这种机制使Wi n d o w s应用程序可以抓住错误并处理错误,再使程序继续运行,不需要用户知道错误的发生。 但是,当e x c e p t块执行后,代码将从何处恢复执行?稍加思索,我们就可以想到几种可能性。
  第一种可能性是从产生异常的C P U指令之后恢复执行。在F u n c m e i s t e r 2中执行将从对d w Te m p加1 0的指令开始恢复。这看起来像是合理的做法,但实际上,很多程序的编写方式使得当前面的指令出错时,后续的指令不能够继续成功地执行。
  在F u n c m e i s t e r 2中,代码可以继续正常执行,但是, F u n c m e i s t e r 2已不是正常的情况。代码应该尽可能地结构化,这样,在产生异常的指令之后的C P U指令有望获得有效的返回值。例如,可能有一个指令分配内存,后面一系列指令要执行对该内存的操作。如果内存不能够被分配,则所有后续的指令都将失败,上面这个程序重复地产生异常。
  这里是另外一个例子,说明为什么在一个失败的C P U指令之后,执行不能够继续。我们用下面的程序行来替代F u n c m e i s t e r 2中产生异常的C语句: 对上面的程序行,编译程序产生C P U指令来执行除法,将结果压入栈中,并调用m a l l o c函数。如果除法失败,代码就不能继续执行。系统必须向栈中压东西,否则,栈就被破坏了。
  所幸的是,微软没有让系统从产生异常的指令之后恢复指令的执行。这种决策使我们免于面对上面的问题。
  第二种可能性是从产生异常的指令恢复执行。这是很有意思的可能性。如果在e x c e p t块中有这样的语句会怎么样呢: 在e x c e p t块中有了这个赋值语句,可以从产生异常的指令恢复执行。这一次,将用2来除5,执行将继续,不会产生其他的异常。可以做些修改,让系统重新执行产生异常的指令。你会发现这种方法将导致某些微妙的行为。我们将在“ EXCEPTION_ CONTINUE_EXECUTION”一节中讨论这种技术。
  第三种可能性是从e x c e p t块之后的第一条指令开始恢复执行。这实际是当异常过滤器表达式的值为E X C E P T I O N _ E X E C U T E _ H A N D L E R时所发生的事。在e x c e p t块中的代码结束执行后,控制从e x c e p t块之后的第一条指令恢复。 If an exception occurs during execution of the guarded section or in any routine the guarded section calls, the __except expression is evaluated and the value determines how the exception is handled. There are three values: 
  EXCEPTION_CONTINUE_EXECUTION (
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics