在极少数确实需要这样做的情况下,可以利用标准库函数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);
- }
- }
- }