在C中,不允许使用跳越函数的g o t o语句。而执行这种跳转功能的是函数s e t j m p和l o n g j m p。这两个函数对于处理发生在很深的嵌套函数调用中的出错情况非常有用.
头文件<setjmp.h>申明了这些函数及同时所需的jmp_buf数据类型。
int setjmp(jmp_buf jmpb) 设置缓冲区来保存堆栈的内容,将保存的上下文存入进程的自身的数据空间(u区),并继续在当前的上下文中执行,一旦碰到了longjmp,进城就从该进程 的u区,取出先前保存的上下文,并恢复该进程的上下文为先前保存的上下文。这时核心将使得进程从setjmp处执行(摘自:unix平台下c语言高级编程 指南)
void longjmp(jmp_buf jmpb, int retval) 使进程返回到 setjmp处执行,retval 表示此时setjmp的返回值。
longjmp必须在setjmp调用之后,而且longjmp必须在setjmp的作用域之内。具体来说,在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到 setjmp的下一条语句执行。实际上setjmp函数将发生调用处的局部环境保存在了一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放 (函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。
setjmp函数的返回值(直接返回时为0,longjmp跳转返回时为longjmp的状态参数retval,根据setjmp的返回值就可以判断程序是 正常执行还是进行异常处理。
举例说明:
static jmp_buf atPrtMenu;
int DemoMenu(void)
{
int selectedItem=0;
int lastItem = -1;
int i;
ixDspCodletFillBaseStrmInfo();
selectedItem = setjmp(atPrtMenu); //设置缓冲区保存堆栈内容
do
{
/* print the test menu */
if(!selectedItem)
{
printf( "/n----------------------------------------/n"
"- Demo Menu -/n"
"----------------------------------------/n");
for (i = 0; Menu[i].name != NULL; i++)
{
printf("%3d - %s/n", i, Menu[i].name);
}
printf("Please select test item - ");
lastItem = i - 1;
}
/* select a menu item */
selectedItem = GetNum(NULL);
/* skip if not a menu item */
if (selectedItem >= lastItem || !selectedItem) continue;
Menu[selectedItem].menuFunc();
} while(selectedItem != lastItem);
return SUCCESS;
}
/**************************
* get an integer for stdin
**************************/
int GetNum(char *str)
{
int c;
int i = 0;
char input[STRLEN];
if(str && *str) printf("%s", str);
do
{
c = getc(stdin);
if (c == 0x08)
{
if(i) i--;
}
else
{
input[i++] = c;
}
/* exception if x entered, jump to main menu */
if(c == 'x') longjmp(atPrtMenu, 1);//返回到setjmp处执行,即重新打印main menu
} while(i<STRLEN && c!='/r' && c!='/n');
input[i] = '/0';
return atoi(input);
}