其实可以通过setjmp()和longjmp()配合使用 描述 和goto很相似, 但是可以从一个函数到另外一个函数的跳转,常常用在异常处理上面. 这两个函数需要正确使用,否则会破坏程序顺序执行方式 头文件 #include <setjmp.h> setjmp()和longjmp() int setjmp(jmp_buf env); 将当前上下文保存在 ,所以会从setjmp函数调用点返回,返回值为val 跳转机制 (以 mian()函数 和 divide()函数 为例): mian()函数 调用了 setjmp(env) ,将上下文(入栈)保存在env 进入 setjmp()函数 后,由于发现除法为0,所以使用 longjmp(env,1)函数 ,恢复 setjmp() 保存的上下文,也就是直接返回到了 main()函数 处理 setjmp(env) ); //手动调用 setjmp(),将返回正常值(0), if(!
而这整个功能的主要依靠setjmp和longjmp来实现。 1 int setjmp(jmp_buf env) setjmp需要被先調用,調用之后,setjmp就保存了一份程序的计数器和当前栈顶指针,当然,根据需要也可以保存一些变量的初始化信息。 使用方法如下面代码所示: #include <stdio.h> #include <setjmp.h> jmp_buf j; int main() { if(setjmp(j)) { void longjmp(jmp_buf env,int val) 在调用了setjmp后调用longjmp可以恢复保存的值并有效的将setjmp保存的计数器和栈信息恢复到之前的状态,这个过程也是堆栈展开的过程 setjmp的返回值,因此TestSuit函数中longjmp后的代码将不被执行。
参考链接: C++ longjmp()和setjmp() 这篇讲的不错: http://blog.csdn.net/smstong/article/details/50728022 首先Active Record 然后EBP,ESP等指针 2 通过setjmp和longjmp操纵AR,完成任意跳转 setjmp/longjmp主要从嵌套的函数调用中跳出来。 #include <stdio.h> #include <setjmp.h> jmp_buf jb; void a(); void b(); void c(); int main() { if( setjmp(jb)==0){ a(); } printf("after a(); \n"); return 0; } void a() { b(); C里面模拟异常的代码大概如下: #include <stdio.h> #include <stdlib.h> #include <setjmp.h> jmp_buf jb; void f1() {
setjmp/longjmp 实现协程 五、总结 一、前言 在 C 标准库中,有两个威力很猛的函数:setjmp 和 longjmp,不知道各位小伙伴在代码中是否使用过? 函数说明 首先来看下这个 2 个函数的签名: int setjmp(jmp_buf env); void longjmp(jmp_buf env, int value); 它们都在头文件 setjmp.h 类似的,setjmp 函数也有不同的返回类型。 也许用返回类型来表述不太准确,可以这样理解:从 setjmp 函数返回,一共有 2 个场景: 主动调用 setjmp 时:返回 0,主动调用的目的是为了保存上下文,建立快照。 有一点需要注意:setjmp/longjmp 仅仅是改变了程序的执行顺序,应用程序自己的一些数据如果需要回滚的话,需要我们自己手动处理。 ? 四、利用 setjmp/longjmp 实现协程 1.
请看实例: // setjmp.c // 非局部跳转测试用例 #include<setjmp.h> #include<stdio.h> jmp_buf b; void jmp_test() { longjmp(b, 1); // 跳到setjmp(b)处,并且指定setjmp(b)返回值为这里的第二个参数 } int main() { if(setjmp(b)) // 正常返回的时候返回 longjmp() 的作用就是让程序的执行流回到当初setjmp()的时刻,并且返回由longjmp指定的返回值(第二个参数) 就好像让程序”时光倒流“。 当然,这绝对不是结构化编程。
一、C语言错误处理方法 1、返回值(if … else语句判断错误) 2、errno(linux 系统调用) 3、goto语句(函数内局部跳转) 4、setjmp、longjmp(Do not use setjmp and longjmp in C++ programs; these functions do not support C++ object semantics. ) # define _JBLEN 16 typedef _JBTYPE jmp_buf[_JBLEN]; Saves the current state of the program. int setjmp value argument of longjmp is 0,setjmp returns 1. value Value to be returned to setjmp call.
和longjmp函数 C语言种,goto是不能跨越函数的,而执行这类跳转功能的函数是setjmp和longjmp。 #include <setjmp.h> int setjmp(jmp_buf env); Returns: 0 if called directly, nonzero if returning from a call to longjmp void longjmp(jmp_buf env, int val); 在要返回的地方调用setjmp。 #include "apue.h" #include <setjmp.h> #define TOK_ADD 5 jmp_buf jmpbuffer; int main(void) { char line[MAXLINE]; if (setjmp(jmpbuffer) !
协程有多种语言的实现方式,对于C语言来说,C标准库里有“非局部跳转”函数setjmp和longjmp,它们分别保存和恢复:栈指针、程序计数器、被调用者保存的寄存器和ABI要求的任何其他内部状态。 VPP协程模型 VPP的协程便是由setjmp/longjmp实现。 使用longjmp/setjmp的轻量级多任务协程,由应用进程自行进行调度,不受操作系统调度机制的影响,上下文切换只损耗调用longjmp/setjmp的时间。 . */ 跳转到setjmp设置点,reurn_value 就是跳转到clib—setjmp返回数值 void clib_longjmp (clib_longjmp_t * save, uword return_value ; otherwise returns value from clib_longjmp if long jump is taken. */ 设置跳转返回点,默认返回 uword clib_setjmp
(3)使用C标准库中非局部跳转函数:setjmp()和longjmp()。 setjmp()函数可在程序中存储一典型的正常状态,如果程序发生错误,longjmp()可恢复setjmp()函数的设定状态,从而实现goto语句无法实现的“长跳转”。 参考下面的使用setjmp()和longjmp()实现“长跳转”的例子。 当初始化完jump的上下文,setjmp()返回0值。 当作为长跳转的目标而再次被调用时,setjmp()返回r或1(如果r设为0的话)。(记住,setjmp()不能在这种情况时返回0)。
0 总结 longjmp与setjmp语句之间的变量赋值会丢失。 变量须满足: 在调用setjmp函数中的局部变量(栈变量) ,全局变量不受影响 非volatile 解决方法:加volatile 1 问题复现 #include <setjmp.h> #include 对比:左侧gcc O0,右侧gcc O1 手册中已有说明,满足三个条件的变量赋值无效: 变量属于setjmp所在函数的局部变量:必须是栈上的变量。 变量在setjmp和longjmp之间有修改。 变量没有volatile。 (3) call; · their values are changed between the calls to setjmp(3) and longjmp(); and
longjmp函数和setjmp函数配合使用。 int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val); 先在程序容易出错的地方使用setjmp,定义一个入口,等到后面代码真的出错之后使用 longjmp跳转到setjmp处。 setjmp直接调用返回0,若从longjmp返回,则为非0. 对上面程序进行解释: 当第一次执行setjmp时,由于是直接调用,所以返回0,接着调用我们的功能函数fun1,假设fun3里面出错了,那么就会通过longjmp跳转到setjmp处,同时携带一个返回值
#ifndef SHOWCRASH_H #define SHOWCRASH_H #include <setjmp.h> #include <signal.h> #include <unistd.h> SETJMP?? * ???SETJMP????SETJMP???CRASH???????SETJMP? * ???SETJMP???CRASH??????? SETJMP */ class ShowCrash { public: ShowCrash(); static void CrashFunction(int); static static int GetIndex(){return buf_index;} static int buf_index; private: }; #define SETJMP (index)\ setjmp(buff[index]);\ ShowCrash::SetIndex(index);\ extern ShowCrash g_showcrash; extern
文章目录 前言 一、c语言中协程切换方式 二、使用setjmp 和 longjmp实现协程切换 1.setjmp和longjmp函数简介 2.协程实现 三、使用switch-case实现协程切换 1 二、使用setjmp 和 longjmp实现协程切换 1.setjmp和longjmp函数简介 setjmp和longjmp是C99标准中<setjmp.h>文件里定义的两个函数,定义如下: int setjmp b.longjmp函数负责跳转到参数 env 中保存的上下文中去执行setjmp函数,并且返回值是longjmp的第二个参数val。 setjmp负责将这些寄存器信息保存到env参数,longjmp跳转时就可以根据保存的env参数重置cpu寄存器的值,从而跳转到指定位置开始执行程序。 2.协程实现 使用setjmp和longjmp简单实现的一个协程切换函数如下所示: #include<setjmp.h> #include<stdio.h> #include<unistd.h> /*
上下文信息保存c 语言使用了jmp_buf 是 c 语言中用于实现非本地跳转,setjmp 函数可以用于保存调用环境信息longjmp 函数可以回复保存的调用环境setjmp 和 longjmp 函数setjmp 函数:int setjmp(jmp_buf env);该函数保存当前的调用环境到 env 中,并返回 0。 当通过 longjmp 跳转到此环境时,setjmp 返回一个非零值。 longjmp 函数:void longjmp(jmp_buf env, int val);该函数恢复 env 保存的调用环境,并导致 setjmp 返回 val。 如果 val 为 0,setjmp 返回 1。这两个函数都保存在头文件#include <setjmp.h> 中。代码实现有了上述的背景铺垫,那么 try-catch 实现相对容易理解一点。
/reference/csetjmp/setjmp/),原因同信号处理。 5. setjmp和longjmp 在C/C++中,goto关键词只能函数内的局部跳转,函数间的跳转需要使用setjmp和longjmp,这也是有些协程库基于setjmp和longjmp实现的原因。 1) setjmp 保存上下文,包括信号掩码,类似于setcontext。 2) longjmp 该函数从不返回,而是跳回到setjmp保存点,类似于swapcontext。如果没有先调用setjmp,则longjmp的行为是未定义的。 2) 结果2(优化编译:g++ -g -o x x.cpp -O2) X::ctor setjmp return: 0 setjmp return
setjmp()函数声明如下: int setjmp(jmp_buf env); jmp_buf是可以保存环境信息的结构体。 它会将程序跳转回setjmp()后面要执行的代码。 但此时setjmp()会返回longjmp()第二个参数val,而不是0。 env是一个此类型的变量,用于在setjmp和longjmp之间传递环境信息。 setjmp函数把当前环境信息保存到env中。 当需要非局部跳转时,调用longjmp(),并将在setjmp()保存的环境作为参数传入。 这个时候程序就会跳转回setjmp()保存的环境,仿佛从setjmp()后面继续执行。 但此时setjmp()会返回非0值。
) { int x = 5; assert(x == 10); // This will fail and abort the program return 0; } 6. setjmp () 和 longjmp() **setjmp()**:setjmp() 用于设置一个恢复点。 如果程序在后续调用 longjmp() 时跳转到该恢复点,setjmp() 会返回一个非零值。 **longjmp()**:longjmp() 用于从 setjmp() 所在的地方跳转到程序的某个恢复点。它可以用于错误处理,但一般不推荐作为常规的错误处理机制。 \n"); longjmp(env, 1); // Jump back to setjmp } int main() { if (setjmp(env) !
使用这条宏引入静态库即可使用: 下面是一个例子: 1 #include<Windows.h> 2 #include <stdio.h> 3 #include "jpeglib.h" 4 #include <setjmp.h struct my_error_mgr { 23 struct jpeg_error_mgr pub; /* "public" fields */ 24 25 jmp_buf setjmp_buffer myerr = (my_error_ptr) cinfo->err; 35 (*cinfo->err->output_message) (cinfo); 36 longjmp(myerr->setjmp_buffer } 54 cinfo.err = jpeg_std_error(&jerr.pub); 55 jerr.pub.error_exit = my_error_exit; 56 if (setjmp (jerr.setjmp_buffer)) { 57 jpeg_destroy_decompress(&cinfo); 58 fclose(infile); 59 return
2,用户态的subroutine切换机制:使用setjmp/longjmp来切换context。 3,O(logn)的高效排序算法:st使用heap排序。 其中context字段就是setjmp/longjmp的参数;left/right字段是在heap中使用的;stack字段就是各个thread的栈。 ? 5,switch context st支持使用glibc的setjmp/longjmp机制,或者由st自己实现的jmp。 由编译选项MD_USE_BUILTIN_SETJMP和USE_LIBC_SETJMP共同控制。看需求,用户自己选择。 6,注意点 st是不支持抢占的!!!
其实,移植ST比想象的要简单很多,最关键的就是实现setjmp/longjmp,也就是保存寄存器和恢复寄存器,所以步骤如下: 1.分析你的平台的寄存器使用,也就是函数调用规范。 etc.) #11[7] Windows x86-64 Dev make cygwin64-debug For Windows(x64) desktop, #20[8] Note: 早期ST直接使用setjmp -_st_md_cxt_restore #endif Note: 实际上,_st_md_cxt_save就是setjmp,而_st_md_cxt_restore就是longjmp。 最后,就是用汇编实现函数,需要找下平台相关的资料(也可以直接通过调试setjmp和longjmp的实现,来学习如何将寄存器保存到jmpbuf,以及如何从jmpbuf恢复),详细参考 #21[13]。 Note: 创建协程时,当时的SP可能是在另外一个协程,所以创建的协程并不能直接使用当前的SP,而需要从堆上重新申请虚拟的stack,所以在setjmp后需要更新jmpbuf中的SP地址。