您的位置:首页 > 编程语言 > C语言/C++

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

2012-05-18 15:15 609 查看
[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 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐