2010年(88)
分类: C/C++
2010-10-06 21:41:46
int setjmp( jmp_buf env );
这是MSDN中对它的评论,如下:
setjmp函数用于保存程序的运行时的堆栈环境,接下来的其它地方,你可以通过调用longjmp函数来恢复先前被保存的程序堆栈环境。当setjmp和longjmp组合一起使用时,它们能提供一种在程序中实现“非本地局部跳转”("non-local goto")的机制。并且这种机制常常被用于来实现,把程序的控制流传递到错误处理模块之中;或者程序中不采用正常的返回(return)语句,或函数的正常调用等方法,而使程序能被恢复到先前的一个调用例程(也即函数)中。
对setjmp函数的调用时,会保存程序当前的堆栈环境到env参数中;接下来调用longjmp时,会根据这个曾经保存的变量来恢复先前的环境,并且当前的程序控制流,会因此而返回到先前调用setjmp时的程序执行点。此时,在接下来的控制流的例程中,所能访问的所有的变量(除寄存器类型的变量以外),包含了longjmp函数调用时,所拥有的变量。
setjmp和longjmp并不能很好地支持C++中面向对象的语义。因此在C++程序中,请使用C++提供的异常处理机制。
好了,现在已经对setjmp有了很感性的了解,暂且不做过多评论,接着往下看longjmp函数。
longjmp函数有何作用?
同样,longjmp也是C标准库中提供的一个函数,它的作用是用于恢复程序执行的堆栈环境,它的函数原型如下:
void longjmp( jmp_buf env, int value );
这是MSDN中对它的评论,如下:
longjmp函数用于恢复先前程序中调用的setjmp函数时所保存的堆栈环境。setjmp和longjmp组合一起使用时,它们能提供一种在程序中实现“非本地局部跳转”("non-local goto")的机制。并且这种机制常常被用于来实现,把程序的控制流传递到错误处理模块,或者不采用正常的返回(return)语句,或函数的正常调用等方法,使程序能被恢复到先前的一个调用例程(也即函数)中。
对setjmp函数的调用时,会保存程序当前的堆栈环境到env参数中;接下来调用longjmp时,会根据这个曾经保存的变量来恢复先前的环境,并且因此当前的程序控制流,会返回到先前调用setjmp时的执行点。此时,value参数值会被setjmp函数所返回,程序继续得以执行。并且,在接下来的控制流的例程中,它所能够访问到的所有的变量(除寄存器类型的变量以外),包含了longjmp函数调用时,所拥有的变量;而寄存器类型的变量将不可预料。setjmp函数返回的值必须是非零值,如果longjmp传送的value参数值为0,那么实际上被setjmp返回的值是1。
在调用setjmp的函数返回之前,调用longjmp,否则结果不可预料。
在使用longjmp时,请遵守以下规则或限制:
· 不要假象寄存器类型的变量将总会保持不变。在调用longjmp之后,通过setjmp所返回的控制流中,例程中寄存器类型的变量将不会被恢复。
· 不要使用longjmp函数,来实现把控制流,从一个中断处理例程中传出,除非被捕获的异常是一个浮点数异常。在后一种情况下,如果程序通过调用_fpreset函数,来首先初始化浮点数包后,它是可以通过longjmp来实现从中断处理例程中返回。
· 在C++程序中,小心对setjmp和longjmp的使用,应为setjmp和longjmp并不能很好地支持C++中面向对象的语义。因此在C++程序中,使用C++提供的异常处理机制将会更加安全。
把setjmp和longjmp组合起来,原来它这么厉害!
////////////////////////////////////////////////////////////////////////
#include
#include
jmp_buf buf;
void banana()
{
printf("in banana\n");
longjmp(buf,1);
printf("You will never see this, because i longjmped\n");
}
int main()
{
if(setjmp(buf))
printf("back in main\n");
else
{
printf("first time in through\n");
banana();
}
return 0;
}
/*
输出:
first time in through
in banana
back in main
*/
////////////////////////////////////////////////////////////////////////
不用OS,俺也能实现多任务切换。算是个“开裆裤”吧
#include
jmp_buf jumper0,jumper1,jumper2,jumper3;
void Task0()
{
static int n=0;
if(setjmp(jumper0)>0)
{
while(1)
{
if(setjmp(jumper0)==0) longjump(jumper1,1); //任务切换
n++; //一段任务代码
if(setjmp(jumper0)==0) longjump(jumper1,1); //任务切换
n++; //一段任务代码
}
}
}
void Task1()
{
static int n=0;
if(setjmp(jumper1)>0)
{
while(1)
{
if(setjmp(jumper1)==0) longjump(jumper2,1);
n++;
if(setjmp(jumper1)==0) longjump(jumper2,1);
n++;
}
}
}
void Task2()
{
static int n=0;
if(setjmp(jumper2)>0)
{
while(1)
{
if(setjmp(jumper2)==0) longjump(jumper3,1);
n++;
if(setjmp(jumper2)==0) longjump(jumper3,1);
n++;
}
}
}
void Task3()
{
static int n=0;
if(setjmp(jumper3)>0)
{
while(1)
{
if(setjmp(jumper3)==0) longjump(jumper0,1);
n++;
if(setjmp(jumper3)==0) longjump(jumper0,1);
n++;
}
}
}
void InitTask()
{
Task0();
Task1();
Task2();
Task3();
}
main()
{
InitTask();
longjmp(jumper0,1)
}
//以上代码在keil c中调试通过
//非占先式任务切换
//任务内变量必须是静态的,子程序不用
//任务内不要用寄存器变量