Loading

setjmp.md

【C】setjmp的用法

https://www.0xaa55.com/thread-424-1-1.html(出处: 技术宅的结界)

setjmp在C语言里用于充当一个可跨函数跳转的跳转标号(可以这么理解。)
首先你需要包含一个头文件:#include<setjmp.h> ,之后就可以使用setjmp了。
方法:

 jmp_buf foo;//定义一个叫foo的“标号”(注意不是真的标号)
 setjmp(foo);//设置这个“标号”的位置是这一行
 longjmp(foo,XX);//跳转到“标号”被设置的位置,并且让跳转后的setjmp返回XX(XX是一个int数值)

请看以下的代码实例:

#include<stdio.h>
#include<conio.h>
#include<setjmp.h>
 
jmp_buf g_ThisJmp;
 
void main(void)
{
    int value;
    char ch;
 
    puts("Hello World!");//卖个萌
 
    value=setjmp(g_ThisJmp);//后面调用longjmp(g_ThisJmp,XX);都会跳转到这一行,XX是setjmp的返回值
    printf("Value=%d\n",value);//打印数值
 
    ch=getch();//让用户按下一个键
    longjmp(g_ThisJmp,ch);//跳转到setjmp(g_ThisJmp)那行,并且把按键值作为setjmp(g_ThisJmp)的返回值
}

这些代码等效于

#include<stdio.h>
#include<conio.h>
 
void main(void)
{
    int value=0;
    char ch;
 
    puts("Hello World!");//卖个萌
 
foobar://定义一个标号
    printf("Value=%d\n",value);//打印数值
 
    ch=getch();//让用户按下一个键
    value=ch;
    goto foobar;//跳转到标号
}

从上面的代码看好像大家觉得setjmp比goto麻烦很多,也不容易理解。但是setjmp能实现跨函数、跨文件的跳转,而goto只能实现函数内的跳转。此外setjmp也可用于“错误处理”。
函数间的跳转示例:

#include<stdio.h>
#include<conio.h>
#include<setjmp.h>
 
jmp_buf g_ThisJmp;
 
void foo()
{
    char ch=getch();
    printf("你按下了%C\n",ch);
    longjmp(g_ThisJmp,ch);//跳转走
 
    puts("这行字符串不可能被打印出来除非出BUG。");
}
 
void main(void)
{
    int value;
 
    puts("Hello World!");//卖个萌
 
    value=setjmp(g_ThisJmp);//后面调用longjmp(g_ThisJmp,XX);都会跳转到这一行,XX是setjmp的返回值
    printf("Value=%d\n",value);//打印数值
 
    foo();
 
    puts("这行字符串不可能被打印出来除非出BUG。");
}

大家可以看出,通过setjmp你可以实现各种范围内的跳转,但是前提是你必须先调用setjmp()函数来设置你的标号的位置,然后才能用longjmp来跳转到指定的位置。下面的代码就无法执行成功:

[C] 纯文本查看 复制代码

?

longjmp(g_ThisJmp,0);//因为g_ThisJmp并没有被初始化,所以这行代码会引发无法预测的异常。
 
setjmp(g_ThisJmp);//只有初始化了g_ThisJmp才能保证longjmp成功

注意事项:
1、不要以为setjmp不会改变寄存器(针对内联汇编等的提示),当你执行了setjmp的时候,寄存器并不会被保存,longjmp跳转回来的时候并不会恢复寄存器的值。
2、不要用setjmp或longjmp在中断处理程序和普通的程序中间跳来跳去,除非你跳转到浮点异常中断的处理程序内或者从浮点异常中断的处理程序内跳出。
3、在C艹的程序里小心使用setjmp,因为setjmp不支持C艹的对象和类。如果你非要用的话也请使用C艹自带的错误处理语句(try...catch)

posted @ 2022-05-27 14:11  nsfoxer  阅读(6)  评论(0编辑  收藏  举报