setjmp & longjmp in C language

最近几天重新把尘封已久的那本Expert C Porgramming拿出来又扫了一遍,发现以前遗漏了好多C语言的特性,看来之前那遍是白看了。

 

书中第六章:运行时数据结构有一小节专门拿出来讲ISO C中的setjmp和longjmp。根据书上的说法,它是为了增强C有限的跳转能力而设的,与goto主要有两点不同: 第一点是goto只能当前函数内跳转,而longjmp允许跳转到其他文件的函数中。但是另一方面,longjmp也有自己的局限性,它只允许“故地重游”,也就是说,longjmp跳转的目标地点之前曾经执行过。这一C语言特性之前编程中从来没有使用过,遂顺手写了段小程序一试。

 

#include <setjmp.h> #include <stdio.h> jmp_buf env; int main() { int i; setjmp(env); printf("Please input an integer: "); if(scanf("%d", &i) == 0) { fflush(stdin); longjmp(env, 1); } else { printf("Your input number: %d/n", i); } return 0; }

 

上面这段程序的功能就是请求用户输入一个整型数然后回显用户输入,主要目的是在错误处理中使用setjmp和longjmp。

 

最开始的时候,忘了用fflush清空输入流,所以scanf对输入进行parse的时候出现异常的话整个程序就死循环了。后来注意到了这个问题,加入了fflush,这段程序用CodeBlocks编辑在windows环境下运行得很好。

 

后来自己心血来潮,用vim在Linux下写了同样的程序,但是程序一旦接收用户非法输入就会毫不留情的crash掉。把源代码看过来看过去,思忖着要出问题也只有可能是scanf。倒腾了半天没折腾出结果,只好把C标准拿出来瞧了下,然后很惊人地发现一段关于fflush函数的描述:

 

int fflush(FILE *stream)

 

On an output stream, fflush causes any buffered but unwritten data to ba written; on an input stream, the effect is undefined. It returns EOF if any errors occurred, and zero otherwise.

 

顿时恍然大悟,fflush原来不能作用于标准输入。想到之前在windows平台下写类似的处理输入的程序一直用fflush清buffer,不禁大汗。遂将程序改为:

 

#include <stdio.h> #include <setjmp.h> #define BUF_SIZE 255 jmp_buf env; int main () { int i; char buff[BUF_SIZE]; setjmp (env); printf ("Please input an integer: "); fgets (buff, BUF_SIZE, stdin); if (sscanf (buff, "%d", &i) == 0) longjmp (env, 1); else printf ("Your input number: %d/n", i); return 0; }

 

这样一来,缓存清空的问题就没有了。当然这个程序也不是完美的,比如int值溢出的问题,当然这不是当前主要关注的。

 

看来以后还是切到Linux环境下用gcc比较可靠,Windows掩盖了一个犯了那么多年的错误!有问题找语言标准总是没错的。

 

参考资料:

[1] Expert C Programming Deep C Secret, Peter Van Der Linden

[2] The C Programming Language, Brian W. Kernighan&Dennis M. Ritchie

 

 

你可能感兴趣的:(setjmp & longjmp in C language)