setjmp()

本文探讨了setjmp与longjmp在C语言中的使用,通过具体代码示例展示了这两个函数如何实现非局部跳转,并分析了在不同编译选项下程序行为的变化,揭示了变量在非局部跳转中的保存与恢复机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

static jmp_buf env;

static void
doJump(int nvar, int rvar, int vvar)
{
    printf("Inside doJump(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar);
    longjmp(env, 1);
}

int
main(int argc, char *argv[])
{
    int nvar;
    register int rvar;          /* Allocated in register if possible */
    volatile int vvar;          /* See text */

    nvar = 111;
    rvar = 222;
    vvar = 333;

    if (setjmp(env) == 0) {     /* Code executed after setjmp() */
        nvar = 777;
        rvar = 888;
        vvar = 999;
        doJump(nvar, rvar, vvar);

    } else {                    /* Code executed after longjmp() */

        printf("After longjmp(): nvar=%d rvar=%d vvar=%d\n", nvar, rvar, vvar);
    }

    exit(EXIT_SUCCESS);
}
 

When we compile the program in Listing 6-6 normally, we see the expected output:
$ cc -o setjmp_vars setjmp_vars.c
$ ./setjmp_vars
Inside doJump(): nvar=777 rvar=888 vvar=999
After longjmp(): nvar=777 rvar=888 vvar=999

 

However, when we compile with optimization, we get the following unexpected
results:
$ cc -O -o setjmp_vars setjmp_vars.c
$ ./setjmp_vars
Inside doJump(): nvar=777 rvar=888 vvar=999
After longjmp(): nvar=111 rvar=222 vvar=999

 

--------------------------------------------------------------------------------------------------------------------------------

这个宏可能不只返回一次。第一次,在直接调用它时,它总是返回零。当调用 longjmp 时带有设置的环境信息,这个宏会再次返回,此时它返回的值会传给 longjmp 作为第二个参数。

#include <stdio.h>

#include <setjmp.h>

static jmp_buf buf;

void second(void)

{

   printf("second\n"); // 打印

   longjmp(buf,1); // 跳回setjmp的调用处 - 使得setjmp返回值为1

}

void first(void) {

   second();

   printf("first\n"); // 不可能执行到此行

}

int main() {

   if ( ! setjmp(buf) )

   {

        first(); // 进入此行前,setjmp返回0

    } else { // 当longjmp跳转回,setjmp返回1,因此进入此行

        printf("main\n"); // 打印

    }

   return 0;

}

 

输出

second
main
03-19
### setjmp 函数的用法及相关信息 `setjmp` 是 C 标准库中的一个重要函数,用于实现非局部跳转(non-local jump)。它通常与 `longjmp` 配合使用,提供了一种控制流转移的方式,可以绕过常规的子程序调用和返回序列。 #### 基本定义 `setjmp` 定义在 `<setjmp.h>` 头文件中。它的主要功能是保存当前执行环境的状态,并将其存储在一个名为 `jmp_buf` 的结构体变量中[^2]。 #### 使用方法 以下是 `setjmp` 和 `longjmp` 的基本用法: 1. **头文件引入** 在使用之前需要包含 `<setjmp.h>` 文件。 ```c #include <setjmp.h> ``` 2. **声明 jmp_buf 变量** 创建一个 `jmp_buf` 类型的变量来保存执行环境的信息。 3. **调用 setjmp** 调用 `setjmp(jmp_buf)` 会保存当前的执行状态到 `jmp_buf` 中并返回 0。如果通过 `longjmp` 返回,则返回值是非零值。 4. **调用 longjmp** 当某个条件满足时,可以通过调用 `longjmp(jmp_buf, value)` 来恢复由 `setjmp` 保存的执行环境。此时,`value` 将作为 `setjmp` 的返回值传递给调用者。 #### 示例代码 下面是一个简单的例子展示如何使用 `setjmp` 和 `longjmp` 实现异常处理的功能。 ```c #include <stdio.h> #include <setjmp.h> jmp_buf buf; void second() { printf("second(): before longjmp()\n"); /* 这里触发了一个非本地跳转 */ longjmp(buf, 1); } void first() { second(); printf("first(): after second()\n"); // 不会被打印出来 } int main() { int ret; if ((ret = setjmp(buf)) == 0) { printf("main(): setjmp returned %d (initial call)\n", ret); first(); // 正常流程进入这里 } else { printf("main(): setjmp returned %d (after longjmp)\n", ret); } return 0; } ``` 运行上述代码的结果如下: ``` main(): setjmp returned 0 (initial call) second(): before longjmp() main(): setjmp returned 1 (after longjmp) ``` 在这个例子中,当 `longjmp` 被调用时,程序立即回到了 `setjmp` 所处的位置,并且其返回值被设置为传入 `longjmp` 的第二个参数。 #### 注意事项 - 如果 `longjmp` 的第二个参数为 0,则 `setjmp` 的返回值将是 1。 - `setjmp` 和 `longjmp` 并不适用于多线程环境中,因为它们只保存单一线程的上下文。 - 应谨慎使用这些函数,过度依赖可能导致代码难以理解和维护。 #### POSIX 支持 除了标准 C 库外,在 POSIX 环境下也可以找到类似的接口支持。需要注意的是,虽然 `<setjmp.h>` 属于 ANSI C 标准的一部分,但它并不属于 POSIX 核心库[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值