【问题标题】:How to use longjmp from main function to other functions?如何从 main 函数使用 longjmp 到其他函数?
【发布时间】:2020-11-03 16:52:24
【问题描述】:
#include <setjmp.h>
#include <stdio.h>

jmp_buf jmp;

int test() {
    setjmp(jmp);
    puts("Birds are crying");
    return 0;
}


int main() {
    longjmp(jmp,1);
    return 0;
}

上面的代码不起作用并崩溃,为什么?

我在 Windows 10 Pro 上使用 GCC 编译器。

【问题讨论】:

  • 您必须创建一个非本地跳转的上下文。因此,必须先调用 setjmp()。
  • 顺便说一句,longjmp 进入函数的目的是什么?
  • @Jabberwocky 教育,我猜。
  • @MarcoBonelli 是的,也许是为了展示未定义行为的表现。
  • 如果您真的想实现这样的目标,我建议您研究(非常小心)使用makecontext/getcontext/swapcontext/@ 987654325@.

标签: c setjmp


【解决方案1】:

您对longjmp()的使用无效,请查看the documentation

longjmp()恢复上次调用setjmp()保存的环境

您需要先调用setjmp(),以便在调用longjump() 之前“设置”跳转的位置。这就是你的代码不起作用的原因。充其量是未定义的行为。

换句话说,您不能只使用longjmp() 作为简单的“跳转到全局标签”。它有不同的目的。


longjmp 行之前调用test(); 后,它可以工作并打印两次,但为什么它仍然崩溃?

我们再来看看the documentation

setjmp() 将堆栈上下文/环境保存在 env 中,供longjmp() 以后使用。如果调用setjmp()的函数返回,堆栈上下文将失效。

您不能将longjmp() 指向先前由现在已返回的函数设置的缓冲区。这是无效的。您对setjmp()/longjmp() 的使用确实不是这些函数的用途。


跳出到另一个函数并不是setjmp()/longjmp() 的真正目的,它们的目的是保存上下文并“跳回”到一个仍未返回的函数(见下面的例子)。想出一个有意义的此类函数的用法示例并不简单,因为它们是为高级用法而设计的。

这是一个正确的用法示例(虽然仍然没有那么有意义)from Wikipedia

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

static jmp_buf buf;

void second() {
    printf("second\n");         // prints
    longjmp(buf,1);             // jumps back to where setjmp was called - making setjmp now return 1
}

void first() {
    second();
    printf("first\n");          // does not print
}

int main() {   
    if (!setjmp(buf))
        first();                // when executed, setjmp returned 0
    else                        // when longjmp jumps back, setjmp returns 1
        printf("main\n");       // prints

    return 0;
}

【讨论】:

  • 是的,但根本没有调用测试函数。
  • @soldiercaptain 是的,但是你没有调用测试函数,所以永远不会调用setjmp()
  • 它仍然崩溃,因为另外,通过setjmp()初始化的跳转缓冲区在执行setjmp()的函数调用返回后变得无效。这意味着,除其他外,没有明确的方法可以使用 longjmp() 从(初始执行)main() 跳转到任何其他函数。
  • @EricPostpischil GCC 在 Windows == Cygwin/MinGW == GNU 标准。 setjmp/longjmp 是 C89,这些链接只是描述其用法的众多链接中的一部分。
  • @soldiercaptain 更新了一个工作示例,跳出另一个函数并不是setjmp/longjmp 的真正目的,目的是“跳回”一个仍然存在的函数未返回。
猜你喜欢
  • 2013-01-12
  • 1970-01-01
  • 2019-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多