C语言的异常机制--setjump()和longjump()实现【转载】

   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

 

猜你喜欢

转载自jimmee.iteye.com/blog/2265248