我第一次使用setjmp和longjmp,我遇到了一个问题,当我包装setjmp和longjmp时。我将代码简化为以下示例:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jb;
int mywrap_save()
{
int i = setjmp(jb);
return i;
}
int mywrap_call()
{
longjmp(jb, 1);
printf("this shouldn't appear\n");
}
void example_wrap()
{
if (mywrap_save() == 0){
printf("wrap: try block\n");
mywrap_call();
} else {
printf("wrap: catch block\n");
}
}
void example_non_wrap()
{
if (setjmp(jb) == 0){
printf("non_wrap: try block\n");
longjmp(jb, 1);
} else {
printf("non_wrap: catch block\n");
}
}
int main()
{
example_wrap();
example_non_wrap();
}
最初我认为example_wrap()和example_non_wrap()的行为相同。但是,运行程序的结果(GCC 4.4,Linux):
wrap: try block
non_wrap: try block
non_wrap: catch block
如果我在gdb中跟踪程序,我看到即使mywrap_save()返回1,返回后的else分支也会被奇怪地忽略。谁能解释一下发生了什么?
答案 0 :(得分:10)
The longjmp() routines may not be called after the routine which called
the setjmp() routines returns.
换句话说,你搞砸了你的筹码。
您可以查看装配体,看看您是否可以拼凑出真正发生的事情。
答案 1 :(得分:1)
setjmp()
将保存当前的调用堆栈并标记一个点。当调用堆栈增长时,无论距标记点多远,您都可以使用longjmp()
转到标记点,就像您从未离开过该点一样。
在你的代码中,当从mywrap_save()
返回时,标记的点不再有效,该点周围的堆栈空间是脏的,因此你不能回到脏点。