今天发现一个特别有意思的函数对,setjmp和longjmp。
setjmp用于保存栈状态到指定buf中,longjmp用于把栈状态回复到指定buf存储的状态,同时返回到setjmp使用的地方。
setjmp第一次的返回值为0,调用longjmp后,执行位置从setjmp返回,返回值为longjmp指定的值。
这个函数对是C语言写的,存在于<setjmp.h>中。
函数声明格式为
extern int setjmp (jmp_buf __env) __THROWNL;
和
extern void longjmp (struct __jmp_buf_tag __env[1], int __val)
__THROWNL __attribute__ ((__noreturn__));
其中
jmp_buf定义为
typedef struct __jmp_buf_tag jmp_buf[1];
__jmp_buf_tag定义为
/* Calling environment, plus possibly a saved signal mask. */
struct __jmp_buf_tag
{
/* NOTE: The machine-dependent definitions of `__sigsetjmp'
assume that a `jmp_buf' begins with a `__jmp_buf' and that
`__mask_was_saved' follows it. Do not move these members
or add others before it. */
__jmp_buf __jmpbuf; /* Calling environment. */
int __mask_was_saved; /* Saved the signal mask? */
__sigset_t __saved_mask; /* Saved signal mask. */
};
下面有个例子,是glibc中的使用范例。基本演示了怎么使用。
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
jmp_buf main_loop;
void
abort_to_main_loop (int status)
{
longjmp (main_loop, status);
}
int
main (void)
{
while (1)
if (setjmp (main_loop))
puts ("Back at main loop....");
else
do_command ();
}
void
do_command (void)
{
char buffer[128];
if (fgets (buffer, 128, stdin) == NULL)
abort_to_main_loop (-1);
else
exit (EXIT_SUCCESS);
}
这个例子基本演示了两个函数是如何运行的。
只是 if (fgets (buffer, 128, stdin) == NULL)在我直接敲回车时还是收到了一个‘\n’,我是改为if (fgets (buffer, 128, stdin)[0] == '\n'),执行的。
还有一个例子,tst-setjmp.c中的例子,比较复杂,我理解是个死循环,估计是理解错了。明天再看看。