setjmp和longjmp函数--非局部跳转语句。
非局部指的是,这不是由普通C语言goto,语句在一个函数内实施的跳转,而是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一个函数中。
#include <setjmp.h>
Int setjmp(jmp_buf env);
返回值:若直接调用则返回0,若从longjmp调用返回则返回非0值void longjmp(jmp_buf env,int val);
在希望返回到的位置调用setjmp,此位置在main函数中,因为直接调用该函数,所以其返回值为0.setjmp参数evn的类型是一个特殊的类型jmp_buf,这一数据类型是某种形式的数组,其中存放在调用longjmp时能用来恢复栈状态的所有信息。因为需要在另一个函数中引用env变量,所以规范的处理方式是将env变量定义为全局变量。应用:
当检查到一个错误时,则以两个参数调用longjmp函数,第一个就是在调用setjmp时所用的env,第二个参数是具有非0值的val,它将成为从setjmp处返回的值。使用第二个参数的原因是对于一个setjmp可以有多个longjmp。
注: longjmp必须在setjmp调用之后,而且longjmp必须在setjmp的作用域之内。具体来说,在一个函数中使用setjmp来初始化一个全局标号,然后只要该函数未曾返回,那么在其它任何地方都可以通过longjmp调用来跳转到 setjmp的下一条语句执行。实际上setjmp函数将发生调用处的局部环境保存在了一个jmp_buf的结构当中,只要主调函数中对应的内存未曾释放 (函数返回时局部内存就失效了),那么在调用longjmp的时候就可以根据已保存的jmp_buf参数恢复到setjmp的地方执行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h> //signal
#include <unistd.h> //alarm
#include <setjmp.h> //setjmp and longjmp
#define MAXBUFFLEN 1024
/*
*使用longjmp 及 alarm实现带超时限制调用read
*/
static void sig_alrm(int signo);//声明alarm信号处理函数
static jmp_buf env_alrm;
int main(int argc, char *argv[])
{
int n;
char buf[MAXBUFFLEN];
memset(buf, 0x00, sizeof(buf));
if(signal(SIGALRM, sig_alrm) == SIG_ERR){
printf("signal(SIGALRM) Error\n");
exit(-1);
}
//第一次调用setjmp会返回0,当longjmp被调用后,代码会跳转到setjmp处执行,setjmp将会返回longjmp设置的值。
if(setjmp(env_alrm) != 0){
printf("read timeout...\n");
exit(-2);
}
alarm(10);
printf("please intupt some char:");
fflush(stdout);
if((n == read(STDIN_FILENO, buf, MAXBUFFLEN)) < 0){
printf("read error...\n");
exit(-3);
}
alarm(0);
//buf[MAXBUFFLEN-1] = '\0';
//printf("%s\n", buf);
write(STDOUT_FILENO, buf, n);
return 0;
}
static void sig_alrm(int signo){
longjmp(env_alrm, 1);
}
[huangbin@devsrv3 ~]$ make setjmp
cc setjmp.c -o setjmp
[huangbin@devsrv3 ~]$ ./setjmp
please intupt some char:read timeout...
[huangbin@devsrv3 ~]$ ./setjmp
please intupt some char:hello,world!
[huangbin@devsrv3 ~]$