我不明白为什么在函数middleFunc()
中,在entry_point(arg)
语句中调用if ( setjmp(middle) )
时会引起分段错误。
#include <stdio.h>
#include <setjmp.h>
jmp_buf start,middle,end;
void finalFunc(void *v)
{
printf("hello\n");
return ;
}
void middleFunc(void (*entry_point)(void *), void *arg)
{
//just debug : this does not cause segmentation fault
entry_point(arg);
if ( setjmp(middle) ){
//this casues the segmentation fault
entry_point(arg);
//once the entry point (finalFunc) is executed go to jmp_buffer end
longjmp(end,1);
}
else {
longjmp(start,1);
}
}
int main(){
if (setjmp(end)){
//exit since finalFunc has been executed
return 0;
}
if (setjmp(start)){
//the middleFunc has previously set the jmp_buffer middle
longjmp(middle,1);
}
else{
int x = 1;
middleFunc(finalFunc,(void*)&x);
}
}
答案 0 :(得分:5)
在您的代码中,行为是未定义的。在middle
完成执行之后(无论是正常完成还是其他middleFunc
),您不允许长时间跳转到longjmp
。
7.13.2.1 longjmp函数
2
longjmp
函数可在与相应的setjmp
相同的程序调用中恢复由jmp_buf
宏的最新调用保存的环境。论点。如果没有这样的调用,或者如果包含setjmp
宏的调用的函数在此期间终止执行 248),则该行为未定义。248)例如,通过执行一条
return
语句,或者由于另一个longjmp
调用已导致嵌套调用集中的函数中的setjmp
调用转移。 / p>
在您的代码中middleFunc
设置了middle
,此后立即执行main
退出到longjmp(start,1)
。跳转之后,middle
不再有效。您不再被允许从任何地方跳到middle
。 setjmp/longjmp
机制仅支持跳转调用堆栈。您不能进行侧跳或下跳。仅支持跳转。
从实际的角度来看,您试图跳入“死”函数调用,并以某种方式期望函数参数值仍然有效(例如,从先前的调用中保留下来的东西)。但事实并非如此。 setjmp/longjmp
不保留/恢复参数值。在该“无效”调用中,entry_point
的值可能为some garbage。当您尝试通过entry_point
进行呼叫时,代码将转储。
P.S。的确,有时会使用setjmp/longjmp
的边跳转来实现协同例程。但是,这种用法超出了标准库规范的范围。而且无论如何,这种用法永远都不会期望保留参数值。