C語言異常處理機制案例講解

2022-09-25 01:15:10 字數 2652 閱讀 6801

異常處理機制:setjmp()函式與longjmp()函式

c標準庫提供兩個特殊的函式:setjmp() 及 longjmp(),這兩個函式是結構化異常的基礎,正是利用這兩個函式的特性來實現異常。

所以,異常的處理過程可以描述為這樣:

首先設定乙個跳轉點(setjmp() 函式可以實現這一功能),然後在其後的**中任意地方呼叫 longjmp() 跳轉回這個跳轉點上,以此來實現當發生異常時,轉到處理異常的程式上,在其後的介紹中將介紹如何實現。

setjmp() 為跳轉返回儲存現場並為異常提供處理程式,longjmp() 則進行跳轉(丟擲異常),setjmp() 與 longjmp() 可以在函式間進行跳轉,這就像乙個全域性的 goto 語句,可以跨函式跳轉。

舉個例子,程式在 main() 函式內使用 setjmp() 設定跳轉,並呼叫另一函式a,函式a內呼叫b,b丟擲異常(呼叫longjmp() 函式),則程式直接跳回到 main() 函式內使用 setjmp() 的地方返回,並且返回乙個值。

jmp_buf 異常結構

使用 setjmp() 及 longjmp() 函式前,需要先認識一下 jmp_buf 異常結構。jmp_buf 將使用在 setjmp() 函式中,用於儲存當前程式現場(儲存當前需要用到的暫存器的值),jmp_buf 結構在 setjmp.h 檔案內宣告:

typedef struct

jmp_buf;

jmp_buf 結構存放了程式當前暫存器的值,以確保使用 longjmp() 後可以跳回到該執行點上繼續執行。

setjmp() 與 longjmp() 函式詳細說明

setjmp() 與 longjmp() 函式原型如下:

void _cdecl longjmp(jmp_buf jmpb, int retval);

int _cdecl setjmp(jmp_buf jmpb);

_cdecl 宣告函式的引數使用標準c的進棧方式(由右向左)壓棧,_cdecl 是c語言的一種呼叫約定,除此以外,pascal 也是呼叫約定之一。c標準呼叫約定(_cdecl)所宣告的函式不自動清除堆疊,這一事務由呼叫者自行負責——這也是c可以支援不固定個數的引數的原因。此外,這一呼叫約定將在函式名前新增乙個下劃線字元,如某一函式宣告為:

int cdecl dosomething(void);

編譯時將自動為 dosomething 加上下劃線字首,即函式名變為: _dosomething。

setjmp() 與 longjwww.cppcns.commp() 函式都使用了 jmp_buf 結構作為形參,它們的呼叫關係是這樣的:

首先呼叫 setjmp() 函式來初始化 jmp_buf 結構變數 jmpb,將當前cpu中的大部分影響到程式執行的暫存器的值存入 jmpb,為 longjmp() 函式提供跳轉,setjmp() 函式是乙個有趣的函式,它能返回兩次,它應該是所有庫函式中唯一乙個能返回兩次的函式,第一次是初始化時,返回零,第二次遇到 longjmp() 函式呼叫後,longjmp() 函式使 setjmp() 函式發生第二次返回,返回值由 longjmp() 的第二個引數給出(整型,這時不應該再返回零)。

在使用 setjmp() 初始化 jmpb 後,可以其後的程式中任意地方使用 longjmp() 函式跳轉會 setjmp() 函式的位置,longjmp() 的第乙個引數便是 setjmp() 初始化的 jmpb,若想跳轉回剛才設定的 setjmp() 處,則 longjmp() 函式的第乙個引數是 setjmp() 所初始化的 jmpb 這個異常,這也說明一件事,即 jmpb 這個異常,一般需要定義為全域性變數,否則,若是區域性變數,當跨函式呼叫時就幾乎無法使用(除非每次遇到函式呼叫都將 jmpb 以引數傳遞,然而明顯地,是不值得這樣做的);longjmp() 函式的第二個引數是傳給 setjmp() 的第二次返回值,這在介紹 setjmp() 函式時已經介紹過。

異常處理過程

先來對比(參考)一下 c++ 的異常處理,c++ 在語言層上便新增了異常處理機制,使用 try 塊來包含那些可能出現錯誤的**,你可以在 try 塊**中丟擲異常,c++ 使用 throw 來丟擲異常。丟擲異常後,將轉到異常處理程式中執cpsjfyudm行,c++ 使用 catch 塊來包含那些處理異常的**,catch 塊可以接收不同型別的異常。需要說明的是,throw 一般不在 try 塊內的**中丟擲異常,try 塊內的**呼叫了別的函式,如函式a,函式a 又呼叫了函式 b,throw 可以在函式b中丟擲異常,或者更深的函式呼叫層,無論如何,只要有異常丟擲,程式將轉到 catch 處執行。

c中如何實現,或者明確地說是模擬這一功能?

下面介紹的是一些簡單的方法。

現在假設 longjmp() 第二個值為1,即 setjmp() 第二次將返回1。我們使用一組簡單的巨集來替代 setjmp() 和 longjmp() 以便使用:

首先定義乙個全域性的異常:

jmp_buf jump_buffer;

因為 setjmp() 第一次呼叫初始化後返回0,第二次返回非0,可以這樣定義乙個巨集使得它功能接近於 c++ 的 try。

#define try if(!setjmp(jump_buffer))

當 setjmp() 函式第一次0 時,取非為真,則執行 try 塊內的**,如:

trycatch

int test_t(int t)

int main()

catch

getch();

return 0;

}

c語言異常處理機制

異常處理機制 setjmp 函式與longjmp 函式 c標準庫提供兩個特殊的函式 setjmp 及 longjmp 這兩個函式是結構化異常的基礎,正是利用這兩個函式的特性來實現異常。所以,異常的處理過程可以描述為這樣 首先設定乙個跳轉點 setjmp 函式可以實現這一功能 然後在其後的 中任意地方...

c 異常處理機制示例及講解

這兩天我寫了乙個測試c 異常處理機制的例子,感覺有很好的示範作用,在此貼出來,給c 異常處理的初學者入門。本文後附有c 異常的知識普及,有興趣者也可以看看。下面的 直接貼到你的console工程中,可以執行除錯看看效果,並分析c 的異常機制。include stdafx.h include incl...

c 異常處理機制示例及講解

這兩天我寫了乙個測試c 異常處理機制的例子,感覺有很好的示範作用,在此貼出來,給c 異常處理的初學者入門。本文後附有c 異常的知識普及,有興趣者也可以看看。下面的 直接貼到你的console工程中,可以執行除錯看看效果,並分析c 的異常機制。include stdafx.h include incl...