c - 为什么 setjmp/longjmp
问题描述
我想使用 setjmp/longjmp 来重用 main 函数中的一些代码(注意:这只是一个练习,并不是我在现实世界中认真计划做的事情)。以下代码是我想出的:
#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)
. - 在记住身体应该使用返回的位置后,
func()
调用将暂时跳转到使用身体longjmp(jmp_body)
if (setjmp(jmp_ret) == 0)
- 主体将执行并
func()
使用longjmp(jmp_ret, 1)
func()
只是要按预期main()
返回。
因此,我期望打印的代码如下:
Body 1
Body 2
Body 3
相反,它永远循环不断地执行主体,这向我表明func()
调用没有返回它应该返回的位置,而是可能会返回到自身之上,一遍又一遍地执行自身。
相比之下,以下代码正是我所期望的:
#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)
一个使原始方法无效的函数调用是什么?
解决方案
TL/DR - 你不能跳回你跳出的函数。
7.13.2.1C 2011 在线草案longjmp
函数
...
2 该函数在程序的同一次调用中longjmp
恢复最近一次调用宏所保存的环境,并带有相应的参数。如果没有这样的调用,或者如果调用来自另一个执行线程,或者如果包含宏调用的函数在中间 终止了执行248),或者如果 宏的调用在具有可变修改类型和执行的标识符在此期间离开了该范围,行为未定义。setjmp
jmp_buf
setjmp
setjmp
248) 例如,通过执行 return 语句或因为另一个longjmp
调用导致转移到setjmp
嵌套调用集中较早的函数中的调用。
当您执行longjmp(jump_body, 1);
in 时func
,您将无效 jump_ret
。
longjmp
不是双向的 - 它展开堆栈,就好像在setjmp
和之间的任何函数调用longjmp
从未发生过一样。
推荐阅读
- sql - 从 Oracle 过程中的 2 个选择语句返回值
- html - IosSlider 不允许在其下方添加内容
- vue.js - 如何在 Vue 中从外部回调中设置数据?
- python - 如何从列表中减去列表?
- c# - 在 asp.net 核心中使用 serilog 维护单独的范围上下文
- php - wp_enqueue_style 媒体查询仍在来源/报道中?
- kubernetes - K8 - 使用 nginx 入口控制器在两个服务之间进行循环负载平衡
- javascript - 图片宽度会影响内容加载速度吗?
- google-sheets - Google 表格 - QUERY - 压缩数据透视表
- ruby-on-rails - 尝试创建删除函数(React 前端/Rails 后端)