在极少数确实需要这样做的情况下,可以利用标准库函数setjmp()和longjmp()实现一种能从一个或多个函数中跳出的跳转(goto)。要正确地使用setjmp()和longjmp()函数,必须满足几个条件。
首先,你必须包含setjmp.h头文件,该文件提供了setjmp()和longimp()函数的原型,并定义了jmp—buf类型。你需要把一个jmp—bur类型的变量作为一个参数传递给setjmp()和longjmp()函数,这个变量将包含使跳转发生所需的信息。
其次,你必须调用setjmp()函数来初始化jmp—bur变量。如果setjmp()函数返回0,则说明jmp_buf变量已被初始化;如果setjmp()函数返回其它值,则说明程序刚才通过调用longjmp()函数跳转到了对应于该值的位置。在后一种情况下,setjmp()函数的返回值就是程序传递给longjmp()函数的第二个参数。
从概念上讲,longjmp()函数的作用就好象是这样:当它被调用时,当前正在执行的函数便会返回;然后,调用这个函数的函数将返回;依此类推,直到调用setjmp()的函数成为正在执行的函数。程序的执行将跳转到调用setjmp()函数的位置,并从setjmp()函数返回那一点继续往下执行,但此时setjmp()函数的返回值已被置为传递给longjmp()函数的第二个参数。
换句话说,如果函数f()调用了setjmp(),然后又调用了函数g(),而函数g()调用了函数h(),函数h()调用了longjmp(),那么程序运行起来就好象h()立即返回了,然后g()立即返回,然后f()执行一次回到调用setjmp()的位置的跳转。
这就是说,为了使对10ngjmp()的调用能正常工作,程序必须已经调用setjmp(),并且还没有从调用setjmp()的函数中返回。如果这些条件得不到满足,那么longjmp()的行为是没有定义的(这意味着你的程序很可能会崩溃)。例12.9中的程序说明了setjmp()和longjmp()的用法。这个程序显然是为此而设计的,因为如果不使用setjmp()和longjmp(),程序就会更简洁些。总的来说,当你想使用setjmp()和longjmp()时,最好先找一种可以不使用它们的编程方法,因为它们容易被误用,并且会使程序难于阅读和维护。
例12.9 一个使用setjmp()和longjmp()的例子
# include <setjmp.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# define RETRY_PROCESS 1
# define QUIT_PROCESS 2
jmp_buf env;
int nitems;
int procItem()
{
char buf[256];
if (gets (buf) &&.strcmp(buf, "done")) {
if (strcmp(buf, "quit") ==0)
longjmp (env, QUIT_PROCESS );
if (strcmp(buf, "restart") ==0)
longjmp(env, RETRY_PROCESS);
nitems+ + ;
return 1;
}
return 0;
}
void
process()
{
printf ("Enter items, followed by 'done'. \n") ;
printf("At any time, you can type 'quit' to exit\n");
printf ("or 'restart' to start over again\n");
nitems = 0;
while (procItem())
}
void
main() {
for (; ;) {
switch (setjmp(env)) {
case 0:
case RETRY_PROCESS:
process () ;
printf("You typed in %d items. \n" ,
nitems);
break ;
case QUIT_PROCESS:
default:
exit(O);
}
}
}