异常处理,保证代码稳定的必经之步----小话c语言(12)

来源:互联网 发布:大数据全洞察 编辑:程序博客网 时间:2024/05/16 10:31

[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];

可以看到jmp_buf是个数组类型,含有18个int类型数据,包括eax, ebp, esp, eip等环境变量。

它会返回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 processvoid 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 processvoid 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 processvoid 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 processvoid 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