C++編譯器怎麼實現異常處理1 (轉)

worldblog發表於2007-12-12
C++編譯器怎麼實現異常處理1 (轉)[@more@]

C++怎麼實現異常處理

:namespace prefix = o ns = "urn:schemas--com::office" />

對於VC++實現異常處理的深入探討

導論

相比較其他傳統的語言,C++的一個變革的特徵是支援異常處理。相對於傳統語言的不清楚容易錯誤的錯誤處理機制,C++的異常處理是一個非常好的替代。在正常的程式碼和錯誤處理程式碼之間清楚的分割使得非常整潔和宜於維護。本文討論編譯器怎麼實現異常處理。假設讀者熟悉異常處理的語法。 本文包含一個異常處理的VC++的庫來替代VC++的異常處理,使用這個:

install_my_handler();

在這以後,程式中發生的任何異常(包含丟擲異常到 stack unwinding,catch塊和繼續)都使用我自己的異常處理庫。

譯者注:當異常出現時,正常的執行流被中斷,異常處理機制開始在當前範圍尋找匹配的處理函式。如果找不到,把當前函式從棧中彈出,在呼叫者中繼續尋找。這個過程稱為tips/tipview.?content_id=1614" target=_blank>stack unwinding

像其他C++特徵一樣,C++的標準並沒有指定異常處理的實現機制。這使得C++實現者可以使用任何實現機制。我將講述VC++怎麼實現的。VC++把異常處理置於SHE(Structured exception hangling)的上面。SHE是操作提供的結構化的異常處理。

SHE導論

在本討論中,我將考慮那些顯式的異常。例如被0除,空指標訪問等。當異常出現,中斷會產生,控制被轉到OS。 OS呼叫異常處理,檢查從異常發出的函式開始的函式呼叫順序,執行stack unwinding和控制轉移。我們可以開發自己的異常處理函式,在OS中註冊。OS就會在異常事件時呼叫它們。

Windows定義了一個特別的結構用來註冊:

EXCEPTION_REGISTRATION:

struct EXCEPTION_REGISTRATION

{

  EXCEPTION_REGISTRATION *prev;

  D handler;

};

要註冊自己的異常處理函式,建立這個結構並將它的地址儲存在段(由FS暫存器指向)的0偏移處。如下面的偽指令:

mov FS:[0], exc_regp

結構中的prev欄位表示EXCEPTION_REGISTRATION連結串列。當我們註冊了這個EXCEPTION_REGISTRATION結構,我們使用這個prev欄位儲存以前註冊的結構的地址。

關於異常回撥函式,windows要求異常處理的訊號,定義在excp.h中:

EXCEPTION_DISPOSITION (*handler)(

  _EXCEPTION_RECORD *ExcRecord,

  void * EstablisherFrame,

  _CONTEXT *ContextRecord,

  void * DispatcherContext);

現在你可以忽略所有的引數和返回型別。下面的程式在OS中註冊了一個異常處理控制程式碼並將產生一個被0除的異常。這個異常被抓到並將列印一個訊息:

#include

#include

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; //will not reach here

}

int g_div = 0;

void bar()

{

  //initialize EXCEPTION_REGISTRATION structure

  EXCEPTION_REGISTRATION reg, *preg = ®

  reg.handler = (DWORD)myHandler;

 

  //get the current head of the exception handling chain 

  DWORD prev;

  _asm

  {

  mov EAX, FS:[0]

  mov prev, EAX

  }

  reg.prev = (EXCEPTION_REGISTRATION*) prev;

 

  //register it!

  _asm

  {

  mov EAX, preg

  mov FS:[0], EAX

  }

  //generate the exception

  int j = 10 / g_div;  //Exception. Div by 0.

}

int main()

{

  bar();

  return 0;

}

/*-------output-------------------

In the exception handler

Just a demo. exiting...

---------------------------------*/

注意:windows嚴格地定義了一個規則:EXCEPTION_REGISTRATION結構應該在棧內,並且要在以前的程式碼的低的地址。規則不滿足,windows將中止程式。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991773/,如需轉載,請註明出處,否則將追究法律責任。

相關文章