为什么 setjmp/longjmp
Why does setjmp/longjmp
我想使用 setjmp/longjmp 在主函数中重用一些代码(注意:这只是一个练习,并不是我在现实世界中认真计划做的事情)。
以下代码是我想出的:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmp_body, jmp_ret;
void func(void)
{
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
}
int main()
{
int x = 0;
if (setjmp(jmp_body) == 1) {
printf("Body %d\n", ++x);
longjmp(jmp_ret, 1);
}
func();
func();
func();
return 0;
}
我期望这段代码的工作方式如下:
main()
函数将记住 'body' 部分的位置并使用 if (setjmp(jmp_body) == 1)
跳过它。
- 在使用
if (setjmp(jmp_ret) == 0)
记住正文应该 return 的位置后,func()
调用将使用 longjmp(jmp_body)
暂时跳转到正文
- 正文将执行并使用
longjmp(jmp_ret, 1)
跳回 func()
调用
func()
正按预期从 return 到 main()
。
因此,我希望代码打印的内容如下:
Body 1
Body 2
Body 3
相反,它会永远循环不断地执行正文,这向我表明 func()
调用没有 return 在它应该在的地方,而是可能 return 在它本身之上一遍又一遍地执行自己。
相比之下,下面的代码打印出我所期望的:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmp_body, jmp_ret;
int main()
{
int x = 0;
if (setjmp(jmp_body) == 1) {
printf("Body %d\n", ++x);
longjmp(jmp_ret, 1);
}
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
return 0;
}
将 if (setjmp(jmp_ret) == 0) longjmp(jmp_body, 1)
放入使原始方法无效的函数调用中是什么意思?
您试图 longjmp
将堆栈从 main()
退回到 func()
。这没有定义。由于 longjmp
本身是一个函数,您很可能最终 longjmp
进入 func
,return 地址是 longjmp
调用自身,因此是一个无限循环。
TL/DR - 你不能跳回你跳出的函数。
7.13.2.1 The longjmp
function
...
2 The longjmp
function restores the environment saved by the most recent invocation of
the setjmp
macro in the same invocation of the program with the corresponding
jmp_buf
argument. If there has been no such invocation, or if the invocation was from
another thread of execution, or if the function containing the invocation of the setjmp
macro has terminated execution248) in the interim, or if the invocation of the setjmp
macro was within the scope of an identifier with variably modified type and execution has
left that scope in the interim, the behavior is undefined.
248) For example, by executing a return statement or because another longjmp
call has caused a
transfer to a setjmp
invocation in a function earlier in the set of nested calls.
C 2011 Online Draft
当你在func
中执行longjmp(jump_body, 1);
时,你无效 jump_ret
.
longjmp
不是双向的 - 它展开堆栈,就好像 setjmp
和 longjmp
之间的任何函数调用从未发生过一样.
我想使用 setjmp/longjmp 在主函数中重用一些代码(注意:这只是一个练习,并不是我在现实世界中认真计划做的事情)。 以下代码是我想出的:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmp_body, jmp_ret;
void func(void)
{
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
}
int main()
{
int x = 0;
if (setjmp(jmp_body) == 1) {
printf("Body %d\n", ++x);
longjmp(jmp_ret, 1);
}
func();
func();
func();
return 0;
}
我期望这段代码的工作方式如下:
main()
函数将记住 'body' 部分的位置并使用if (setjmp(jmp_body) == 1)
跳过它。- 在使用
if (setjmp(jmp_ret) == 0)
记住正文应该 return 的位置后, - 正文将执行并使用
longjmp(jmp_ret, 1)
跳回 func()
正按预期从 return 到main()
。
func()
调用将使用 longjmp(jmp_body)
暂时跳转到正文
func()
调用
因此,我希望代码打印的内容如下:
Body 1
Body 2
Body 3
相反,它会永远循环不断地执行正文,这向我表明 func()
调用没有 return 在它应该在的地方,而是可能 return 在它本身之上一遍又一遍地执行自己。
相比之下,下面的代码打印出我所期望的:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmp_body, jmp_ret;
int main()
{
int x = 0;
if (setjmp(jmp_body) == 1) {
printf("Body %d\n", ++x);
longjmp(jmp_ret, 1);
}
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
return 0;
}
将 if (setjmp(jmp_ret) == 0) longjmp(jmp_body, 1)
放入使原始方法无效的函数调用中是什么意思?
您试图 longjmp
将堆栈从 main()
退回到 func()
。这没有定义。由于 longjmp
本身是一个函数,您很可能最终 longjmp
进入 func
,return 地址是 longjmp
调用自身,因此是一个无限循环。
TL/DR - 你不能跳回你跳出的函数。
7.13.2.1 TheC 2011 Online Draftlongjmp
function
...
2 Thelongjmp
function restores the environment saved by the most recent invocation of thesetjmp
macro in the same invocation of the program with the correspondingjmp_buf
argument. If there has been no such invocation, or if the invocation was from another thread of execution, or if the function containing the invocation of thesetjmp
macro has terminated execution248) in the interim, or if the invocation of thesetjmp
macro was within the scope of an identifier with variably modified type and execution has left that scope in the interim, the behavior is undefined.
248) For example, by executing a return statement or because anotherlongjmp
call has caused a transfer to asetjmp
invocation in a function earlier in the set of nested calls.
当你在func
中执行longjmp(jump_body, 1);
时,你无效 jump_ret
.
longjmp
不是双向的 - 它展开堆栈,就好像 setjmp
和 longjmp
之间的任何函数调用从未发生过一样.