[Mac 10.7.1 Lion Intel-based x64 gcc4.2.1]
Q: c语言的异常处理可以使用什么?
A: 可以使用setjmp和longjmp的组合。一个是保存处理异常前执行的环境,一个是调回原来执行的环境。
int setjmp(jmp_buf env);参数env的类型jmp_buf定义如下:
/* * _JBLEN is number of ints required to save the following: * eax, ebx, ecx, edx, edi, esi, ebp, esp, ss, eflags, eip, * cs, de, es, fs, gs == 16 ints * onstack, mask = 2 ints */ #define _JBLEN (18) typedef int jmp_buf[_JBLEN];
它会返回0,便于外部判断进入异常处理逻辑。
void longjmp(jmp_buf env, int val);第一个参数为setjmp设置的jmp_buf, 第二个参数为返回异常处理的异常参数,可自定义。
下面是个简单的例子:
#include <stdio.h> #include <string.h> #include <setjmp.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define PRINT_STR(str) printf(#str" is %s\n", (str)); jmp_buf buf; // exception process void exception_process() { printf("exception process begin...\n"); longjmp(buf, 1); // return to the normal process printf("never execute this...\n"); // so, this line can't be executed } int main() { int ret; printf("main begin...\n"); ret = setjmp(buf); // save current execute enviroment, go to exception process if(ret) { // returned by exception process printf("pass exception process ...\n"); printf("main end ...\n"); } else { exception_process(); } return 0; }可以看到setjmp和longjmp因为共同操作了jmp_buf buf;全局变量,所以它们可以在不同函数跳转并正确返回执行。main函数开始setjmp(buf)一定会返回0, 所以进入exception_process例程,进入后,longjmp(buf, 1);会返回之前执行的地方,进入main的if(ret)逻辑中,执行异常发生后的代码。
执行结果:
Q: 上面代码中的buf全局变量可以采用局部变量吗?
A: 是的,但是需要将buf传递给异常处理部分。如下代码:
#include <stdio.h> #include <string.h> #include <setjmp.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define PRINT_STR(str) printf(#str" is %s\n", (str)); // exception process void exception_process(jmp_buf buf) { printf("exception process begin...\n"); longjmp(buf, 1); // return to the normal process printf("never execute this...\n"); // so, this line can't be executed } int main() { jmp_buf buf; int ret; printf("main begin...\n"); ret = setjmp(buf); // save current execute enviroment, go to exception process if(ret) { // returned by exception process printf("pass exception process ...\n"); printf("main end ...\n"); } else { exception_process(buf); } return 0; }可以看到exception_process多了一个参数,用于buf的传递。
运行结果:
Q: 如果异常原因有几种,怎么分辨处理?
A: 这个就需要用到longjmp第二个参数了。
#include <stdio.h> #include <string.h> #include <setjmp.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define PRINT_STR(str) printf(#str" is %s\n", (str)); // input error process void exception_input_error_process(jmp_buf buf) { printf("exception input error process begin...\n"); longjmp(buf, 1001); // return to the normal process, 1001 means exception error number } // input too big process void exception_input_too_big_process(jmp_buf buf) { printf("exception input too big process begin...\n"); longjmp(buf, 1002); // return to the normal process, 1002 means exception error number } int main() { jmp_buf buf; int ret, scanf_ret; int n; printf("main begin...\n"); // input n printf("input n:"); scanf_ret = scanf("%d", &n); ret = setjmp(buf); // save current execute enviroment, go to exception process if(ret) { // returned by exception process printf("pass exception process ...\n"); if(ret == 1001) { printf("exception 1001 process end...\n"); } else if(ret == 1002) { printf("exception 1002 process end...\n"); } printf("main end ...\n"); } else { if(scanf_ret < 1) exception_input_error_process(buf); else if(n > 100) exception_input_too_big_process(buf); } return 0; }如上,如果输入整形格式不正确,那么进入输入错误处理;如果输入的整形超过100,那么进入输入过大的处理。
运行结果:
输入错误数据a:
输入数据为101:
输入数据50:
此时没有发生异常。
xichen
2012-5-18 15:18:16