(P49)异常:C语言错误处理方法,C++异常处理方法,C++异常处理优点

1.C语言错误处理方法

  • 返回值(if … else语句判断错误)
eg:写个小程序:源文件拷贝到目标文件
int copy(const char* src, char* dst)
{
	open(src);
		return -1;
	open(dst);
		return -2;
	read(src, buf);
		return -3;
	write(dst, buf);
		return -4;
	return 0;
}

调用copy程序的函数
void fun()
{
	int ret;
	ret = copy(src, dst);
	if (ret == -1)
	{
	}
	else if (ret == -2)
	{
	}
	else if (ret == -3)
	{
	}
	else if (ret == -4)
	{
	}

	ret = copy(src, dst);
	if (ret == -1)
	{
	}
	else if (ret == -2)
	{
	}
	else if (ret == -3)
	{
	}
	else if (ret == -4)
	{
	}

}

如果漏掉一次copy,这段if else语句的错误判断还需要重新编写一遍,每调用一次就需要重新编写,
这比较繁琐;
这种错误处理方法也比较容易漏掉某个条件,容易将某种错误忽略掉
  • errno
Linux系统调用与C库函数
错误的话,返回值是-1,并且置errno相应的错误代码
  • goto语句,局部跳转,只能在函数内部进行跳转
int test()
{
	char* p1 = (char*)malloc(10);
	if (p1 != NULL)
	{
		...
	}
	else
	{
		goto POS1;
	}
	char* p2 = (char*)malloc(10);
	if (p2 != NULL)
	{
		...
	}
	else
	{
		goto POS2;
	}
...
...
POS1:
	free(p1);
	exit(1);
POS2:
	free(p2);
	exit(1);
}
  • setjmp,longjmp长跳转(这种跳转不会调用对象析构函数,因为对象不能被正常清理),与C++异常处理很像
    特点:错误的抛出点与错误处理点相隔的距离较远
    eg:P49\01.cpp
#include <stdio.h>
#include <setjmp.h>

//jmp_buf这实际上是一个数组类型
jmp_buf buf;

double Divide(double a, double b)
{
    if (b == 0.0)
    {
        //抛出异常
        longjmp(buf, 1);//这里进行了一次长跳转,它可以跳转到另外的函数,而go to只能在函数内部跳转,
                        //这里长跳转会跳转到buf保存点的位置: ret = setjmp(buf);,然后继续执行
                        //然而这次的返回值是1(返回值根据longjmp的第二个参数来决定),所以会输出:divisiong by zero
                        //相当于C++中的异常的抛出点throw
    }
    else
    {
        return a / b;
    }
    
}

int main(void)
{
    int ret;
    //栈stack环境保存在buf中
    //设置一个保存点buf,保存成功返回0
    ret = setjmp(buf);//首先保存程序的运行环境到buf缓冲区中
    if (ret == 0)//第一次保存总是成功的,所以进入到=0,输出:division...    
    {             //相当于C++的try
        printf("division...\n");
        printf("%f\n", Divide(5.0, 0.0));//接着执行Divide函数
    }
    else if(ret == 1)//相当于C++中的catch,对抛出的异常进行处理
    {
        printf("divisiong by zero\n");
    }

    return 0;
}

测试:
这里ret == 0,ret == 1都进入了
在这里插入图片描述

按下F1获取帮助
在这里插入图片描述

jmp_buf为啥是一个数组类型?点进去看看
在这里插入图片描述

  • C语言的出错处理被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编写错误处理代码,这会使得其变得笨拙以及难以使用。
fun3内部有错误处理,fun2内部有错误处理,fun1内部有异常处理
int fun1()
{
	ret = fun2()
		ret = func3()
}


C++异常处理
异常都能通过catch语句块进行处理,而不需要对返回值一个一个判断
try
{
	fun1();
}
catch(int)
{
}

2.C++异常处理方法

  • try
  • catch
  • throw
  • eg:P49\02.cpp
#include <isotream>
using namespace std;


//jmp_buf这实际上是一个数组类型
jmp_buf buf;

double Divide(double a, double b)
{
    if (b == 0.0)
    {
        //抛出异常
        throw 1;        //throw
    }
    else
    {
        return a / b;
    }
    
}

int main(void)
{
    try     //try  
    {             
        
        cout<<"division..."<<endl;
        //多次调用Divide,也没必要多次对Divide的返回值进行判断,因为现在是通过try。。。catch的
        //方式捕获异常,如果用返回值来判断错误的话,每次调用Divide都要判断它的错误而进行错误处理
        cout<<Divide(3.0, 0.0)<<endl;//只要其中一个出现了错误就会被捕捉到
        cout<<Divide(5.0, 0.0)<<endl;
    }
    //异常发生的地点与异常处理的地点可以相隔很远
    catch(int)//catch捕获整型异常
    {
        cout<<"divisiong by zero\n"<<endl;
    }

    return 0;
}
  • 测试:
    在这里插入图片描述

3.C++异常处理优点

  • 错误处理代码的编写不再冗长乏味,并且不再与“正常”代码混合在一起。
    程序员可以将注意力集中于正常流程,然乎在某个区域里编写异常处理代码。
    如果多次调用同一个函数,只需在一个地方编写一次错误处理代码。
  • 错误不能被忽略
©️2020 CSDN 皮肤主题: 点我我会动 设计师:上身试试 返回首页