上一篇文章對C語言中的goto語句進行了較深入的闡述,實際上goto語句是面向過程與面向結(jié)構(gòu)化程序語言中,進行異常處理編程的最原始的支持形式。后來為了更好地、更方便地支持異常處理編程機制,使得程序員在C語言開發(fā)的程序中,能寫出更高效、更友善的帶有異常處理機制的代碼模塊來。于是,C語言中出現(xiàn)了一種更優(yōu)雅的異常處理機制,那就是setjmp()函數(shù)與longjmp()函數(shù)。
實際上,這種異常處理的機制不是C語言中自身的一部分,而是在C標準庫中實現(xiàn)的兩個非常有技巧的庫函數(shù),也許大多數(shù)C程序員朋友們對它都很熟悉,而且,通過使用setjmp()函數(shù)與longjmp()函數(shù)組合后,而提供的對程序的異常處理機制,以被廣泛運用到許多C語言開發(fā)的庫系統(tǒng)中,如jpg解析庫,加密解密庫等等。
也許C語言中的這種異常處理機制,較goto語句相比較,它才是真正意義上的、概念上比較徹底的,一種異常處理機制。作風一向比較嚴謹、喜歡刨根問底的主人公阿愚當然不會放
棄對這種異常處理機制進行全面而深入的研究。下面一起來看看。
setjmp函數(shù)有何作用?
前面剛說了,setjmp是C標準庫中提供的一個函數(shù),它的作用是保存程序當前運行的一些狀態(tài)。它的函數(shù)原型如下:
int setjmp( jmp_buf env );
這是MSDN中對它的評論,如下:
setjmp函數(shù)用于保存程序的運行時的堆棧環(huán)境,接下來的其它地方,你可以通過調(diào)用longjmp函數(shù)來恢復先前被保存的程序堆棧環(huán)境。當setjmp和longjmp組合一起使用時,它們能提供一種在程序中實現(xiàn)“非本地局部跳轉(zhuǎn)”("non-local goto")的機制。并且這種機制常常被用于來實現(xiàn),把程序的控制流傳遞到錯誤處理模塊之中;或者程序中不采用正常的返回(return)語句,或函數(shù)的正常調(diào)用等方法,而使程序能被恢復到先前的一個調(diào)用例程(也即函數(shù))中。
對setjmp函數(shù)的調(diào)用時,會保存程序當前的堆棧環(huán)境到env參數(shù)中;接下來調(diào)用longjmp時,會根據(jù)這個曾經(jīng)保存的變量來恢復先前的環(huán)境,并且當前的程序控制流,會因此而返回到先前調(diào)用setjmp時的程序執(zhí)行點。此時,在接下來的控制流的例程中,所能訪問的所有的變量(除寄存器類型的變量以外),包含了longjmp函數(shù)調(diào)用時,所擁有的變量。
setjmp和longjmp并不能很好地支持C++中面向?qū)ο蟮恼Z義。因此在C++程序中,請使用C++提供的異常處理機制。
好了,現(xiàn)在已經(jīng)對setjmp有了很感性的了解,暫且不做過多評論,接著往下看longjmp函數(shù)。
longjmp函數(shù)有何作用?
同樣,longjmp也是C標準庫中提供的一個函數(shù),它的作用是用于恢復程序執(zhí)行的堆棧環(huán)境,它的函數(shù)原型如下:
void longjmp( jmp_buf env, int value );
這是MSDN中對它的評論,如下:
longjmp函數(shù)用于恢復先前程序中調(diào)用的setjmp函數(shù)時所保存的堆棧環(huán)境。setjmp和longjmp組合一起使用時,它們能提供一種在程序中實現(xiàn)“非本地局部跳轉(zhuǎn)”("non-local goto")的機制。并且這種機制常常被用于來實現(xiàn),把程序的控制流傳遞到錯誤處理模塊,或者不采用正常的返回(return)語句,或函數(shù)的正常調(diào)用等方法,使程序能被恢復到先前的一個調(diào)用例程(也即函數(shù))中。
對setjmp函數(shù)的調(diào)用時,會保存程序當前的堆棧環(huán)境到env參數(shù)中;接下來調(diào)用longjmp時,會根據(jù)這個曾經(jīng)保存的變量來恢復先前的環(huán)境,并且因此當前的程序控制流,會返回到先前調(diào)用setjmp時的執(zhí)行點。此時,value參數(shù)值會被setjmp函數(shù)所返回,程序繼續(xù)得以執(zhí)行。并且,在接下來的控制流的例程中,它所能夠訪問到的所有的變量(除寄存器類型的變量以外),包含了longjmp函數(shù)調(diào)用時,所擁有的變量;而寄存器類型的變量將不可預料。setjmp函數(shù)返回的值必須是非零值,如果longjmp傳送的value參數(shù)值為0,那么實際上被setjmp返回的值是1。
在調(diào)用setjmp的函數(shù)返回之前,調(diào)用longjmp,否則結(jié)果不可預料。
在使用longjmp時,請遵守以下規(guī)則或限制:
· 不要假象寄存器類型的變量將總會保持不變。在調(diào)用longjmp之后,通過setjmp所返回的控制流中,例程中寄存器類型的變量將不會被恢復。
· 不要使用longjmp函數(shù),來實現(xiàn)把控制流,從一個中斷處理例程中傳出,除非被捕獲的異常是一個浮點數(shù)異常。在后一種情況下,如果程序通過調(diào)用 _fpreset函數(shù),來首先初始化浮點數(shù)包后,它是可以通過longjmp來實現(xiàn)從中斷處理例程中返回。
· 在C++程序中,小心對setjmp和longjmp的使用,應為setjmp和longjmp并不能很好地支持C++中面向?qū)ο蟮恼Z義。因此在C++程序中,使用C++提供的異常處理機制將會更加安全。
把setjmp和longjmp組合起來,原來它這么厲害!
現(xiàn)在已經(jīng)對setjmp和longjmp都有了很感性的了解,接下來,看一個示例,并從這個示例展開分析,示例代碼如下(來源于MSDN):
/* FPRESET.C: This program uses signal to set up a
* routine for handling floating-point errors.
*/
#include
#include
#include
#include
#include
實際上,這種異常處理的機制不是C語言中自身的一部分,而是在C標準庫中實現(xiàn)的兩個非常有技巧的庫函數(shù),也許大多數(shù)C程序員朋友們對它都很熟悉,而且,通過使用setjmp()函數(shù)與longjmp()函數(shù)組合后,而提供的對程序的異常處理機制,以被廣泛運用到許多C語言開發(fā)的庫系統(tǒng)中,如jpg解析庫,加密解密庫等等。
也許C語言中的這種異常處理機制,較goto語句相比較,它才是真正意義上的、概念上比較徹底的,一種異常處理機制。作風一向比較嚴謹、喜歡刨根問底的主人公阿愚當然不會放
棄對這種異常處理機制進行全面而深入的研究。下面一起來看看。
setjmp函數(shù)有何作用?
前面剛說了,setjmp是C標準庫中提供的一個函數(shù),它的作用是保存程序當前運行的一些狀態(tài)。它的函數(shù)原型如下:
int setjmp( jmp_buf env );
這是MSDN中對它的評論,如下:
setjmp函數(shù)用于保存程序的運行時的堆棧環(huán)境,接下來的其它地方,你可以通過調(diào)用longjmp函數(shù)來恢復先前被保存的程序堆棧環(huán)境。當setjmp和longjmp組合一起使用時,它們能提供一種在程序中實現(xiàn)“非本地局部跳轉(zhuǎn)”("non-local goto")的機制。并且這種機制常常被用于來實現(xiàn),把程序的控制流傳遞到錯誤處理模塊之中;或者程序中不采用正常的返回(return)語句,或函數(shù)的正常調(diào)用等方法,而使程序能被恢復到先前的一個調(diào)用例程(也即函數(shù))中。
對setjmp函數(shù)的調(diào)用時,會保存程序當前的堆棧環(huán)境到env參數(shù)中;接下來調(diào)用longjmp時,會根據(jù)這個曾經(jīng)保存的變量來恢復先前的環(huán)境,并且當前的程序控制流,會因此而返回到先前調(diào)用setjmp時的程序執(zhí)行點。此時,在接下來的控制流的例程中,所能訪問的所有的變量(除寄存器類型的變量以外),包含了longjmp函數(shù)調(diào)用時,所擁有的變量。
setjmp和longjmp并不能很好地支持C++中面向?qū)ο蟮恼Z義。因此在C++程序中,請使用C++提供的異常處理機制。
好了,現(xiàn)在已經(jīng)對setjmp有了很感性的了解,暫且不做過多評論,接著往下看longjmp函數(shù)。
longjmp函數(shù)有何作用?
同樣,longjmp也是C標準庫中提供的一個函數(shù),它的作用是用于恢復程序執(zhí)行的堆棧環(huán)境,它的函數(shù)原型如下:
void longjmp( jmp_buf env, int value );
這是MSDN中對它的評論,如下:
longjmp函數(shù)用于恢復先前程序中調(diào)用的setjmp函數(shù)時所保存的堆棧環(huán)境。setjmp和longjmp組合一起使用時,它們能提供一種在程序中實現(xiàn)“非本地局部跳轉(zhuǎn)”("non-local goto")的機制。并且這種機制常常被用于來實現(xiàn),把程序的控制流傳遞到錯誤處理模塊,或者不采用正常的返回(return)語句,或函數(shù)的正常調(diào)用等方法,使程序能被恢復到先前的一個調(diào)用例程(也即函數(shù))中。
對setjmp函數(shù)的調(diào)用時,會保存程序當前的堆棧環(huán)境到env參數(shù)中;接下來調(diào)用longjmp時,會根據(jù)這個曾經(jīng)保存的變量來恢復先前的環(huán)境,并且因此當前的程序控制流,會返回到先前調(diào)用setjmp時的執(zhí)行點。此時,value參數(shù)值會被setjmp函數(shù)所返回,程序繼續(xù)得以執(zhí)行。并且,在接下來的控制流的例程中,它所能夠訪問到的所有的變量(除寄存器類型的變量以外),包含了longjmp函數(shù)調(diào)用時,所擁有的變量;而寄存器類型的變量將不可預料。setjmp函數(shù)返回的值必須是非零值,如果longjmp傳送的value參數(shù)值為0,那么實際上被setjmp返回的值是1。
在調(diào)用setjmp的函數(shù)返回之前,調(diào)用longjmp,否則結(jié)果不可預料。
在使用longjmp時,請遵守以下規(guī)則或限制:
· 不要假象寄存器類型的變量將總會保持不變。在調(diào)用longjmp之后,通過setjmp所返回的控制流中,例程中寄存器類型的變量將不會被恢復。
· 不要使用longjmp函數(shù),來實現(xiàn)把控制流,從一個中斷處理例程中傳出,除非被捕獲的異常是一個浮點數(shù)異常。在后一種情況下,如果程序通過調(diào)用 _fpreset函數(shù),來首先初始化浮點數(shù)包后,它是可以通過longjmp來實現(xiàn)從中斷處理例程中返回。
· 在C++程序中,小心對setjmp和longjmp的使用,應為setjmp和longjmp并不能很好地支持C++中面向?qū)ο蟮恼Z義。因此在C++程序中,使用C++提供的異常處理機制將會更加安全。
把setjmp和longjmp組合起來,原來它這么厲害!
現(xiàn)在已經(jīng)對setjmp和longjmp都有了很感性的了解,接下來,看一個示例,并從這個示例展開分析,示例代碼如下(來源于MSDN):
/* FPRESET.C: This program uses signal to set up a
* routine for handling floating-point errors.
*/
#include
#include
#include
#include
#include

