【问题标题】:Is it allowed to do longjmp() multiple times for one setjmp() call?是否允许一次 setjmp() 调用多次执行 longjmp() ?
【发布时间】:2021-01-18 08:20:35
【问题描述】:

在我的理解中,setjmp()longjmp() 的典型用法是异常处理(libpng 中的用法应该是一个著名的例子),最多只能调用一次longjmp() 一次@ 987654328@电话。

这样的setjmp() 调用多次longjmp() 是否安全?

#include <stdio.h>
#include <setjmp.h>

jmp_buf jb;
int i;

int main(void) {
    i = 0;
    setjmp(jb);
    printf("%d\n", i);
    i++;
    if (i < 10) longjmp(jb, 1);
    return 0;
}

Output:

0
1
2
3
4
5
6
7
8
9

我成功地从这次执行中得到了预期的输出,但这能保证吗? 或者当longjmp() 用于此目的时,jmp_buf 是否会失效?

setcontext - Wikipedia 说“它们可能被视为 setjmp/longjmp 的高级版本;而后者只允许单个非本地跳转堆栈”,但我没有找到禁止多次使用 @ 的描述987654335@ like this from N1570 7.13 Nonlocal jumps .

我知道不鼓励使用setjmp()longjmp(),但我想知道在使用循环语句(forwhiledo-while)和goto 时是否可以将它们用作解决方法语句被禁止,但在某些编程测验中不禁止使用setjmp()longjmp()。 (使用递归可能是此类测验的答案,但在尝试处理需要多次迭代的大数据时存在堆栈溢出的风险)

【问题讨论】:

  • 只要设置跳转缓冲区的上下文(称为setjmp())还没有退出,所以存储的值仍然有效。
  • 第 7.13.2.1 节第 2 节列出了未定义 longjmp(env) 的情况。没有提到重复使用相同的环境。
  • @Barmar - 不确定这是否意味着太多。该标准允许通过遗漏来定义事物。
  • @StoryTeller-UnslanderMonica 没错,但这种哲学可能会让几乎所有事情都变得不确定。它是否明确表示您可以多次读取一个变量?
  • @NateEldredge:大概可以安排重新调用setjmp();如果跳转上下文只能使用一次,您的使用似乎不会变得不可能,尽管重用它似乎确实更容易。

标签: c language-lawyer setjmp


【解决方案1】:

这样的一次 setjmp() 调用是否可以安全地执行 longjmp() 多次?

可以构造一个严格遵从的程序,多次调用longjmp() 以返回到同一个setjmp() 调用的点。它归结为抽象机的状态,包括内存内容,尤其是jmp_buf 的状态,其中setjmp() 调用记录了返回到该调用点所需的状态。该标准规定

所有可访问对象都有值,并且所有其他组件 抽象机有状态,截至longjmp 函数是 被称为,除了[...可以避免或制作的细节 无关紧要的...]。

(C2018 7.13.2.1/3)

特别是,这意味着longjmp() 调用不能更改它从中获取信息的jmp_buf 的值,并且在其他地方不能有任何隐藏状态longjmp() 可以更新以标记相应的@ 987654329@ 已用完。如果机器状态允许符合要求的longjmp() 调用,则在相应的setjmp() 调用返回结果第二个(或第三个,)之后,等效的longjmp() 调用必须仍然符合要求。

【讨论】:

  • 请注意,如果 jmp_buf 是 setjmp 范围内的自动局部变量,则情况并非如此——在这种情况下,您省略的 [...details] 起作用并且其值变得不确定
  • 请注意,如果i 被定义为本地自动变量,则longjmp() 之后的值可能会或可能不会被setjmp() 保留,因此行为将是未定义的。
  • @ChrisDodd 该标准规定,如果在 setjmplongjmp 调用之间修改对象的值,则该值将变得不确定。 jmp_buf 之间有修改吗?
  • @LanguageLawyer:人们会假设 setjmp 本身会在被调用后修改 jmp_buf。但我同意这似乎没有任何理由会导致任何问题。
  • @ChrisDodd 有人会假设 setjmp 本身会在调用后修改 jmp_buf 也许你的意思是 when 调用,而不是 after我>?
猜你喜欢
  • 2018-04-20
  • 2011-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多