持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
最近在做南京大学蒋炎岩老师的操作系统课程,实验M2是实现一个协程库,其中提到了 setjmp 和 longjmp ,这个之前在学习c 语言的时候还没有注意到过,所以就在这里总结一下他们的作用和用法。
在 C 语言中,我们不能使用 goto 语句来跳转到另一个函数中的某个 label 处;但提供了两个函数——setjmp 和 longjmp来完成这种类型的分支跳转。后面我们会看到这两个函数在处理异常上面的非常有用。
setjmp 和 longjmp 使用方法
我们都知道要想在一个函数内进行跳转,可以使用 goto 语句(在很多教科书上其实是并不推荐 使用 goto 语句的,因为goto语句的 存在会影响程序按照顺序执行的过程,给人一种跳来跳去的感觉,比较影响程序的可读性。)
但是如果遇到一下场景,可以很方便的为我们提供便利。
label
for (int i; i<n; i++) {
for (int j; j<n; j++) {
if {
·····
}else{
// goto label
}
}
}
goto 语句可以很方便的让我们跳出多成堆叠的层次。(但这些内容仅仅限于单一个程序内部)
但如果从一个函数内跳转到另一个函数的某处,goto 是不能完成的,那该如何实现呢?
-
函数栈帧,主要是栈帧指针BP和栈顶指针SP
-
程序指针PC,此处为指向 Label 语句的地址
-
其它寄存器,这是和体系相关的,在 x86 体系下需要保存有的 AX/BX/CX 等等 callee-regs。
-
参数 env 是由 setjmp 函数保存过的上下文。
-
参数 val 表示从 longjmp 函数传递给 setjmp 函数的返回值,如果 val 值为0, setjmp 将会返回1,否则返回 val。
-
longjmp 不直接返回,而是从 setjmp 函数中返回,longjmp 执行完之后,程序就像刚从 setjmp 函数返回一样。
i = 0
i = 2
这个操作十分有用,他可以让我们实现一些神奇的操作 比如说 在c 语言里边儿 实现 python 里边儿 的yield 操作。