setjmp與longjmp包含在頭文件/usr/include/setjmp.h中,使用前應(yīng)在程序頭部加入#include <setjmp.h>。
setjmp與longjmp結(jié)合使用時,它們必須有嚴格的先后執(zhí)行順序,也即先調(diào)用setjmp函數(shù),之后再調(diào)用longjmp函數(shù),以恢復(fù)到先前被保存的“程序執(zhí)行點”。否則,如果在setjmp調(diào)用之前,執(zhí)行l(wèi)ongjmp函數(shù),將導(dǎo)致程序的執(zhí)行流變的不可預(yù)測,很容易導(dǎo)致程序崩潰而退出。
setjmp與longjmp的作用同goto語句類似,它能實現(xiàn)本地的跳轉(zhuǎn).
一.setjmp與logjmp的使用場合:
1.人們對于goto語句的忌諱,很多的專業(yè)書籍以及專業(yè)人士號召限制goto語句的使用,此時,setjmp與longjmp對goto語句有了很好的替代作用.
2.goto語句有一個局限性,它只能在函數(shù)內(nèi)部跳轉(zhuǎn).而setjmp與longjmp可以在整個程序全局中跳轉(zhuǎn),實現(xiàn)"長跳轉(zhuǎn)",彌補了goto功能的局限.
3.使用setjmp和longjmp可以捕捉程序中的異常,并采取異常處理機制.
二.使用setjmp設(shè)置跳轉(zhuǎn)點,longjmp回到原設(shè)置點
setjmp與longjmp必須結(jié)合起來使用;
函數(shù)原型:int setjmp(jmp_buf env);
setjmp(env):設(shè)置jumper點,jumper是一個jmp_buf類型變量.在setjmp.h文件中有jmp_buf的定義,可見它是一個結(jié)構(gòu)體數(shù)組.
/* Calling environment, plus possngibly a saved signal mask. */
typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */
{
/* NOTE: The machine-dependent definitions of `__sigsetjmp'
assume that a `jmp_buf' begins with a `__jmp_buf' and that
`__mask_was_saved' follows it. Do not move these members
or add others before it. */
__jmp_buf __jmpbuf; /* Calling environment. */
int __mask_was_saved; /* Saved the signal mask? */
__sigset_t __saved_mask; /* Saved signal mask. */
} jmp_buf[1];
調(diào)用該函數(shù)對env初始化,初始化后返回一個int值,第一次調(diào)用,這個int值為0;
函數(shù)原型:void longjmp(jmp_buf env, int val);
第一個參數(shù):setjmp(env)設(shè)置的jumper點.
第二個參數(shù):給setjmp(env)重新賦值,為val值.
例:
#include <stdio.h>
#include <setjmp.h>
void subroutine(void);
void subroutine_2(void);
jmp_buf jumper;
main()
{
int value;
int i = 0;
value = setjmp(jumper); /* 設(shè)置jump點,初始化jumper,返回值0賦給value, */
i++;
printf("執(zhí)行第[%d]次:value = [%d]: >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n",i,value );
if(value == 0)
{
printf("[1]About to call subroutine.....\n");
subroutine(); /* 調(diào)轉(zhuǎn)到subroutine()函數(shù) */
printf("Never go this....\n");
}
else if(value == 1)
{
printf("[2]About to call subroutine.....\n");
subroutine_2(); /* 調(diào)轉(zhuǎn)到subroutine_2()函數(shù) */
printf("Never go this....\n");
}
else
{
printf("[3]Never go this....\n");
}
return 0;
}
void subroutine(void)
{
/* 調(diào)轉(zhuǎn)到j(luò)umper初始化的地方,即setjmp(jumper)處,并將1賦給set(jumper) */
longjmp(jumper,1);
return;
}
void subroutine_2(void)
{
/* 調(diào)轉(zhuǎn)到j(luò)umper初始化的地方,即setjmp(jumper)處,并將3賦給set(jumper) */
longjmp(jumper,3);
return;
}
三.使用setjmp,longjmp處理異常.
#include <stdio.h>
#include <setjmp.h>
jmp_buf jumper;
void exception();
int deal_exception();
main()
{
int value;
int i = 0;
value = setjmp(jumper); /* 設(shè)置jump點,初始化jumper,返回值0賦給value, */
if ( 0 == value ) {
exception();
}
else {
switch ( value )
{
case 1:
printf( "解決異常情況[%d]\n",value );
break;
case 2:
printf( "解決異常情況[%d]\n",value );
break;
case 3:
printf( "解決異常情況[%d]\n",value );
break;
default:
printf( "異常情況[%d]未知\n",value );
break;
}
}
}
void exception()
{
int _err_no;
if ( _err_no = 3 ) {
printf("出現(xiàn)異常情況[%d]\n",_err_no);
longjmp(jumper,_err_no);
}
return;
}