[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
#include
#include
#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
#include
#include
#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
#include
#include
#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