longjmp

来自cppreference.com
< c‎ | program
在标头 <setjmp.h> 定义
void longjmp( jmp_buf env, int status );
(C11 前)
_Noreturn void longjmp( jmp_buf env, int status );
(C11 起)
(C23 前)
[[noreturn]] void longjmp( jmp_buf env, int status );
(C23 起)

载入先前调用 setjmp 保存的执行环境 env。此函数不返回。转移控制流到设置 env 的宏 setjmp 的调用方。该 setjmp 会返回作为 status 传递的值。

若调用 setjmp 的函数已退出(通过返回或通过另一到栈上更高处的 longjmp),则行为未定义。换言之,只有调用栈间的长跳转是允许的。

跨线程跳转(若调用 setjmp 的函数被另一线程执行)亦是未定义行为。

(C11 起)

若在调用 setjmp 时,VLA 或其他可变修改类型的变量在作用域中,并且控制流离开了该作用域,则 longjmp 到该 setjmp 将引发未定义行为,即使控制流仍然留在该函数内。

在上溯栈的途中,longjmp 不会解分配任何 VLA,若其的生存期以此方式终结,则会出现内存泄漏:

void g(int n)
{
    int a[n]; // a 仍为已分配
    h(n); // 不返回
}
void h(int n)
{
    int b[n]; // b 仍为已分配
    longjmp(buf, 2); // 可能因为 h 的 b 和 g 的 a 导致内存泄漏
}
(C99 起)

参数

env - 引用 setjmp 所保存的程序执行状态的变量
status - 要从 setjmp 返回的值。若它等于 0,则代之以 1

返回值

(无)

注意

longjmp 是有意用以处理非预期的错误条件的,该条件下函数无法有意义地返回。这与其他编程语言中的异常处理相似。

示例

#include <stdio.h>
#include <setjmp.h>
#include <stdnoreturn.h>
 
jmp_buf my_jump_buffer;
 
noreturn void foo(int status) 
{
    printf("foo(%d) called\n", status);
    longjmp(my_jump_buffer, status + 1); // 将从 setjmp 返回 status+1
}
 
int main(void)
{
    volatile int count = 0; // setjmp 作用域中修改的局部变量必须为 volatile
    if (setjmp(my_jump_buffer) != 5) // 在 if 中与常量比较
        foo(++count);
}

输出:

foo(1) called
foo(2) called
foo(3) called
foo(4) called

引用

  • C17 标准(ISO/IEC 9899:2018):
  • 7.13.2.1 The longjmp macro (第 191-192 页)
  • C11 标准(ISO/IEC 9899:2011):
  • 7.13.2.1 The longjmp macro (第 263-264 页)
  • C99 标准(ISO/IEC 9899:1999):
  • 7.13.2.1 The longjmp macro (第 244-245 页)
  • C89/C90 标准(ISO/IEC 9899:1990):
  • 4.6.2.1 The longjmp function

参阅

保存上下文
(宏函数)