情况一:
之前,我们提到了防御性编程,就是说我们预判一些可能出现的问题,然后进行相应的处理。 但是,这些处理往往是在函数中进行的。
比如,判断数组下标是否合法。 -》 if(下标 < 0){ 相应的处理 };
如上,这些异常在函数中进行处理。会使得函数中多出很多处理的代码,但是在使用异常处理机制之后,在函数中遇到异常之后,我们可以将异常抛出,然后再使用到函数的地方再检测和处理异常,这样函数中就是简单的功能实现了。
情况二:
就是如果在函数中遇到了错误,我们不进行处理,我们会给调用者返回一个错误符号(数字等),来表示操作异常。
比如,判断数组下标是否合法。 -》 if(下标 < 0){return -1};
如上,发生异常就返回给调用者一个错误符号(此处为-1),但是如果我们的函数调用有多层呢? 那么只能一层一层的向上级返回这个错误信号,直到最终的调用方。 在使用了异常机制之后,我们就可以一步到位,直接返回到最上级的调用方。
下面代码是在没有使用异常机制情况下,对相应的情况进行处理。
代码: 将一个源文件中的内容拷贝到另外一个目标文件中去。
#define BUFFER_SIZE 1024// 将一个文件中的内容拷贝到另外一个文件中去
int makeFile(const char* dest, const char* src) {// 定义文件指针FILE* fp1 = NULL, * fp2 = NULL;// 打开文件, 以只读二进制形式打开文件,打开失败返回NULLfp1 = fopen(src, "rb"); // 判断文件是否成功打开if (!fp1) {return -1; // 返回错误标记,表示源文件打开失败}// 打开文件,以只写二进制形式打开文件,打开失败返回NULLfp2 = fopen(dest, "wb");// 判断文件是否成功打开if (!fp2) {return -2; // 返回错误标记,表示目标文件打开失败}// 进行文件的拷贝char buffer[BUFFER_SIZE]; // 1024字节的缓存int readLen, writeLen; // 每次读取的长度和写入的长度// 读取的长度大于0,说明有内容可以写入,执行循环体的写入内容while ((readLen = fread(buffer, 1, BUFFER_SIZE, fp1)) > 0) {writeLen = fwrite(buffer, 1, readLen, fp2);// 如果一次写入的长度和读取的长度不等,那么说明写入失败if (readLen != writeLen) {return -3; // 返回错误标记,写入失败}}// 关闭文件fclose(fp1);fclose(fp2);return 0; // 一切正常返回0
}int makeFile2(const char* dest, const char* src) {int ret;ret = makeFile(dest, src);printf("makeFile2 函数被调用");return ret;
}int main(void) {int ret = 0;ret = makeFile2("dest.txt", "src.txt");// 根据不同的返回信号进行相应的处理if (ret < 0) {switch (ret) {case -1:printf("源文件打开失败\n");break;case -2:printf("目的文件打开失败\n");break;case -3:printf("文件信息写入打开失败\n");break;}}system("pause");return 0;
}
一.
按照正常情况,代码会运行成功的,我们手动的将源文件src.txt删除掉,再去执行代码。会打印源文件打开失败。
原因: 以只读形式打开文件,如果文件不存在就打开失败,fp1中为NULL返回-1,然后进行处理,打印信息。
二.
上面代码中,我们还写了一个中间函数makeFile2,目的是为了能够体现,上面说到的使用函数返回错误标志必须一级一级的跳转。 makeFile函数先将错误标记返回到makeFile2函数,然后makeFile2函数再将错误标记返回给main函数。
我们在makeFile2中return之前打印一句话,来观察返回错误信息时的过程。会发现错误信息只有通过makeFile2的return才能返回到main函数中。
使用异常机制可以优化这个过程。