goto语句可以用于同一个函数内异常处理,不幸的是,goto是本地的,它只能跳到所在函数内部的标号上。为了解决这个限制,C函数库提供了setjmp()和longjmp()函数,它们分别承担非局部标号和goto作用。头文件<setjmp.h>申明了这些函数及同时所需的jmp_buf数据类型。
1.setjmp(jbuf)设置“jump”点,用正确的程序上下文填充jmp_buf对象jbuf。这个上下文包括程序存放位置、栈和框架指针,其它重要的寄存器和内存数据。当初始化完jump的上下文,setjmp()返回0值。
2. 以后调用longjmp(jbuf,r)的效果就是一个非局部的goto或“长跳转”到由jbuf描述的上下文处(也就是到那原来设置jbuf的setjmp()处)。当作为长跳转的目标而被调用时,setjmp()返回r (或1,如果r设为0的话)。(setjmp()不能在这种情况时返回0,否则就和设置jump点的返回值冲突了)
#include "apue.h"
#include <setjmp.h>
#define TOK_ADD 5
jmp_buf jmpbuffer;
int
main(void)
{
char line[MAXLINE];
if (setjmp(jmpbuffer) != 0)
printf("error");
while (fgets(line, MAXLINE, stdin) != NULL)
do_line(line);
exit(0);
}
...
void
cmd_add(void)
{
int token;
token = get_token();
if (token < 0) /* an error has occurred */
longjmp(jmpbuffer, 1);
/* rest of processing for this command */
}
setjump和longjump返回时对auto变量、register变量、volatile变量和静态变量的恢复情况示例。cc -O选项表示编译优化。
longjump返回时一般情况下不会恢复到setjump时的值,此种情况属于未定义。
如果你不想让anto变量的值回滚,需要加上volatile属性。
#include "apue.h"
#include <setjmp.h>
static void f1(int, int, int, int);
static void f2(void);
static jmp_buf jmpbuffer;
static int globval;
int
main(void)
{
int autoval;
register int regival;
volatile int volaval;
static int statval;
globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;
if (setjmp(jmpbuffer) != 0) {
printf("after longjmp:\n");
printf("globval = %d, autoval = %d, regival = %d,"
" volaval = %d, statval = %d\n",
globval, autoval, regival, volaval, statval);
exit(0);
}
/*
* Change variables after setjmp, but before longjmp.
*/
globval = 95; autoval = 96; regival = 97; volaval = 98;
statval = 99;
f1(autoval, regival, volaval, statval); /* never returns */
exit(0);
}
static void
f1(int i, int j, int k, int l)
{
printf("in f1():\n");
printf("globval = %d, autoval = %d, regival = %d,"
" volaval = %d, statval = %d\n", globval, i, j, k, l);
f2();
}
static void
f2(void)
{
longjmp(jmpbuffer, 1);
}
$ cc testjmp.c compile without any optimization
$ ./a.out
in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
after longjmp:
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
$ cc -O testjmp.c compile with full optimization
$ ./a.out
in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
after longjmp:
globval = 95, autoval = 2, regival = 3, volaval = 98, statval = 99