setjmp longjmp

来源:互联网 发布:自学java难度大吗 编辑:程序博客网 时间:2024/06/10 16:48

在 C 语言中,我们不能使用 goto 语句来跳转到另一个函数中的某个 label 处;但提供了两个函数——setjmp 和 longjmp来完成这种类型的分支跳转。后面我们会看到这两个函数在处理异常上面的非常有用。

setjmp 和 longjmp 使用方法

我们都知道要想在一个函数内进行跳转,可以使用 goto 语句(不知怎么该语句在中国学生眼中就是臭名昭著,几乎所有国内教材都一刀切地教大家尽量不要使用它,但在我看来,这根本不是语言的问题,而是使用该语言的人,看看 Linux 内核中遍地是 goto 语句的应用吧!),但如果从一个函数内跳转到另一个函数的某处,goto 是不能完成的,那该如何实现呢?

函数间跳转原理

我们要实现的一个 GOTO 语句(我自己定义的),能实现在函数间进行任意跳转,如下例,在函数 g() 中有条语句GOTO Label; 可以跳转到 f() 函数的 Label: 标签所指向的位置,那么我们该如何实现呢?

void f()
{
//…
Label:
//…
}

void g()
{
//…
GOTO Label;
//…
}

首先我们要知道,实现这种类型的跳转,和操作系统中任务切换的上下文切换有点类似,我们只需要恢复 Label 标签处函数上下文即可。函数的上下文包括以下内容:

函数栈帧,主要是栈帧指针BP和栈顶指针SP
程序指针PC,此处为指向 Label 语句的地址
其它寄存器,这是和体系相关的,在 x86 体系下需要保存有的 AX/BX/CX 等等 callee-regs。
这样,在执行 GOTO Label; 这条语句,我们恢复 Label 处的上下文,即完成跳转到 Label 处的功能。

如果你读过 Linux 操作系统进程切换的源码,你会很明白 Linux 会把进程的上下文保存在 task_struct 结构体中,切换时直接恢复。这里我们也可以这样做,将 Label 处的函数上下文保存在某个结构体中,但执行到 GOTO Label 语句时,我们从该结构体中恢复函数的上下文。

这就是函数间进行跳转的基本原理,而 C 语言中 setjmp 和 longjmp 就为我们完成了这样的保存上下文和切换上下文的工作。

函数原型

include

0 0
原创粉丝点击