setjmp and longjmp

本文介绍了C语言中setjmp和longjmp函数的作用与用法,包括如何利用这两个函数实现跨函数的错误处理,以及它们对自动变量、寄存器变量和易变变量的影响。

setjmp, sigsetjmp - save stack context for nonlocal goto

1.作用

C中我们不能goto一个其他函数离得label,我们必须使用setjmplongimp来完成这种类型的branching

2.stack frame

每个function中的自动变量都保存在stack frame

系统内部并有没有支持stack的硬件,C的实现可能会使用链表来实现stack frames

3.example:多层嵌套的程序

figure 7.10
问题:如果内部深层次的函数出现了错误,会一层层返回。而使用setjmplongjmp能解决这个问题。

5.原型

#include <setjmp.h>

int setjmp(jmp_buf env);
//Returns: 0 if called directly, nonzero if returning from a call to longjmp

void longjmp(jmp_buf env, int val);

setjmp的参数env是特殊的能保存所有值的数组。setjmp第一次返回0,之后调用longjmp后,会返回longjmpval值。

下图是调用longjmp后的stack frames
figure7.12

6. automatic,register and volatile variables

值是否回退取决于具体的实现

在完全优化的情况下:
如果不希望变量值回退(roll back)到第一次调用setjmp之前的值,需要加上volatile或者是static变量

为register变量和auntomatic变量会回退到调用setjmp之前的值

举例说明

例如自动变量 int a = 10,在调用setjmp之后的一段时间里a的值变成了66。后来出现错误调用了longjmp,这时候从setjmp处返回。此时a的值回退为之前的10。如果a为volatile变量,那么值仍然为66。

setjmp是一个C库中的函数,用于在程序执行时保存当前执行上下文,并在稍后的时间点从该点重新开始执行。在MIPS汇编中,可以使用jr指令来实现类似的功能。下面是一个示例程序: ``` #include <setjmp.h> #include <stdio.h> jmp_buf env; int f(jmp_buf env) { int val = setjmp(env); printf("f's val = %d\n", val); return val; } int main() { int val = f(env); printf("main's val = %d\n", val); if (val != 0) { printf("longjmp to f()\n"); longjmp(env, val+1); } return 0; } ``` 在这个程序中,我们定义了一个保存执行上下文的jmp_buf类型的变量env。在f函数中,我们调用setjmp函数来保存当前执行上下文,并返回一个值。在main函数中,我们调用f函数,并检查返回值是否为0。如果不是0,则说明在f函数中调用了longjmp函数,需要恢复f函数的执行上下文。我们使用longjmp函数来实现这个功能。 在实际的MIPS汇编代码中,我们需要使用jr指令来实现这个过程。具体实现方法如下: ``` .text setjmp: # Save register values and return address addi $sp, $sp, -12*4 sw $ra, 0($sp) sw $s0, 4($sp) sw $s1, 8($sp) addi $v0, $sp, 12*4 jr $ra longjmp: # Restore register values and return address lw $ra, 0($sp) lw $s0, 4($sp) lw $s1, 8($sp) addi $sp, $sp, 12*4 # Set return value addi $v0, $a1, 1 jr $ra ``` 在setjmp函数中,我们将寄存器中的值保存到堆栈中,并将堆栈指针减小12*4字节(因为我们保存了3个寄存器的值)。然后,我们返回一个指向保存执行上下文的堆栈位置的指针。在longjmp函数中,我们将堆栈中保存的值恢复到寄存器中,并将堆栈指针增加12*4字节。最后,我们将返回值设置为传入的参数值加1,并跳转到保存的返回地址处。这个返回地址就是执行setjmp函数时保存的返回地址。 使用setjmplongjmp函数可能会导致程序的可移植性问题,因为不同的平台可能实现方式不同。因此,应该避免在生产代码中频繁使用这些函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值