1、goto语句,函数内部的短转移
goto语句只能跳转的到本函数内部的标签处,这个没得说,例子如下:
#include <stdio.h> int main() { int i=0; loop: printf("do something %d/n",i); i++; if(i<6) goto loop; return 0; }
2、setjmp 和 longjmp 实现长跳转
函数原型如下:
#include <setjmp.h>
int setjmp(jmp_buf envbuf);
void longjmp(jmp_buf envbuf, int val);
其中 setjmp用来设置一个供longjmp调至的地址envbuf,初次执行setjmp返回0值,程序继续向下执行,
当遇到longjmp调用返回到该处是,促使该函数返回val值,这也就是longjmp的第二个参数,通过这种方式
使得longjmp在跳转的时候可以传递一定的信息给setjmp,可以用来分析跳转原因,方便程序按照不同的返
回值进行不同的处理。
#include <setjmp.h> #include <stdio.h> #include <signal.h> jmp_buf buf; void handler(int signal) { if(signal==SIGINT) printf("Recived SIGINT ,go back to main/n"); longjmp(buf,1); } int main() { signal(SIGINT,handler); if(setjmp(buf)) { printf("Back in main,infinite loop begins/n"); } else printf("infinite loop begins/n"); loop: goto loop; }
上面的函数通过在信号捕捉函数中调用longjmp使得程序能返回到main函数继续执行,所以
setjmp和longjmp的一个很显然的用途就是,从一些非致命行程序错误中返回,使得程序继续
执行。
但是在上面的例子中存在一个问题,当进程第一次接受到SIG_INT信号(Ctrl+C)后成功返回main中,但是
以后接受到SIG_INT信号却不做任何动作了。原因何在呢?因为:
调用l o n g j m p时有一个问题。当捕捉到一个信号时,进入信号捕捉函数,此时当前信号被
自动地加到进程的信号屏蔽字中。这阻止了后来产生的这种信号中断此信号处理程序。如果用
l o n g j m p跳出此信号处理程序,则对此进程的信号屏蔽字会发生什么呢?一般实现是不会恢复
原来的信号屏蔽字的,所以SIG_INT信号被屏蔽了,以后不再响应了。
在4 . 3 + B S D下,s e t j m p和l o n g j m p保存和恢复信号屏蔽字。但是, S V R 4并不
做这种操作。4 . 3 + B S D提供函数_ s e t j m p和_ l o n g j m p,它们也不保存和恢复信号屏
蔽字。
为了允许两种形式并存, P O S I X . 1并没有说明s e t j m p和l o n g j m p对信号屏蔽字的作用,而是
定义了两个新函数s i g s e t j m p和s i g l o n g j m p。在信号处理程序中作非局部转移时应当使用这两个
函数。函数原型如下:
#include <setjmp.h>
int sigsetjmp( sigjmp_buf * env, int savemask );
void siglongjmp ( sigjmp_buf * env, int val );
如果调用sigsetjmp时 参数savemask 为非0,则siglongjmp 从信号处理函数返回时,将恢复进程调用sigsetjmp之前的信号屏蔽字。
将上面的例子改成使用这对函数,就可以继续对SIG_INT信号进行捕捉和从其中返回main了。
#include <setjmp.h> #include <stdio.h> #include <signal.h> sigjmp_buf buf; void handler(int signal) { if(signal==SIGINT) printf("Recived SIGINT ,go back to main/n"); siglongjmp(buf,1); } int main() { signal(SIGINT,handler); if(sigsetjmp(buf,1)) { printf("Back in main/n"); } else printf("infinite loop begins/n"); loop: goto loop; }
2011-04-14