Yan`s Notepad

--- My Notepad......Articles, tools and etc.
C语言实现长跳转(setjmp)
setjmp是C语言的一个函数,目的是为了实现任意位置的跳转。我最开始见到这个函数是在某些开源编译器的源代码中,它负责在遇到语法错误的时候,直接跳出,而不是一级级的往上传递。个人感觉这个函数很方便,因此还是记录一下。
setjmp和longjmp是C语言独有的,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,按照程序员的预先设计的意图,去实现对程序中可能出现的异常进行集中处理。它被定义在<setjmp.h>中:
__declspec(noreturn) void __cdecl longjmp(
    _In_ jmp_buf _Buf,
    _In_ int     _Value
);
int __cdecl setjmp(
    _Out_ jmp_buf _Buf
);
其中,setjmp函数用_Buf保存系统堆栈的内容,以便后续的longjmp函数使用。setjmp函数初次启用时返回0值,而longjmp函数中的参数_Buf是由setjmp函数所保存的堆栈环境,参数_Value是setjmp函数的返回值。longjmp无返回值,它执行后跳转到之前保存了_Buf参数的setjmp函数位置,并由setjmp返回,此时setjmp的返回值是_Value。用一个例子解释:
jmp_buf   jump;
void test()
{
    printf("run: test\n");
    longjmp(jump, 123);                     // 进行跳转
    printf("return: test\n");
}

int main()
{
    int ret;
    ret = setjmp(jump);
    printf("setjmp_return=%d\n", ret);
    if (ret == 0)                           // 初次调用setjmp
    {
        printf("call: test\n");
        test();
    }
    system("pause");
    return 0;
}
当然,如果你使用C#等,或许不会忘记try...catch这样的东西。但是这里毕竟是C语言对吧?
上面的代码展示了这两个函数的使用,调用longjmp之后,将会返回到setjmp的位置,同时setjmp会返回_Value的值。这个就是之前的描述的具体过程。个人认为,该函数在某些地方可以非常有用——因为可以任意跳转。我们也可以根据这个返回值,进行对应的处理。比如在错误处理中,我们可以使用它把错误全部汇总过来,而不是一个个的分散开。
但是要慎用此函数,因为同goto类似,用得太多会把整个程序变得混乱不堪。不过合理使用还是很棒的了。