第63课 C语言异常处理
2018-01-29 14:35
274 查看
1、异常的概念
1.1、程序在运行过程中可能产生异常1.2、异常(Exception)与Bug的区别
1.2.1、异常是程序运行时可预料的执行分支
1.2.2、Bug是程序是的错误,是不被预期的运行方式
2、异常和Bug的对比
2.1、异常:如运行时产生除0的情况、需要打开的外部文件不存在、数组访问时越界2.2、Bug:如使用野指针、堆数组使用结束后未释放、选择排序无法处理长度为0的数组
3、
C语言经典处理方式:if-else
3.1、示例程序void func(…)
{
if(判断是否产生异常)
{
正常情况代码逻辑
}
else
{
异常情况代码逻辑
}
}
/*************** 除法操作异常处理 ************/
#include <iostream>
using namespace std;
double divide(double a, double b, int* valid)
{
const double delta = 0.0000000000000001;//因为double在内存中是不精确的,所以需要这样判断。
double ret = 0;
if(!( (-delta<b) && (b<delta) ))
{
ret = a/b;
*valid = 1; //正常
}
else
{
*valid = 0;//除0错误
}
return ret;
}
//如果只有两个参数,那么异常为0和实际为0无法分辨。
int main()
{
int valid = 0;
double r = divide(1, 0, &valid); //当第三个参数为NULL,还是会出问题,段错误。
if(valid)
{
cout << "r = " << r << endl;
}
else
{
cout << "Divide by Zero....." << endl;
}
return 0;
}
3.2、缺陷
3.2.1、divide函数有3个参数,难以理解其用途
3.2.2、divide函数调用后必须判断valid代表的结果:true表示结果正常,false表示出现异常
4、C语言异常处理的优化方式
4.1、通过setjmp()和longjmp()进行优化4.1.1、包含头文件#include <setjmp.h>或<csetjmp>
4.1.2、int
setjmp(jmp_buf env):将当前上下文保存在jum_buf结构体中,以供以后longjmp()恢复状态信息时使用。如果是直接调用setjmp(),那么返回值为0;如果是由于调用longjmp()而调用setjmp(),那么返回值非0。setjmp()只能在某些特定情况下调用,如在if语句、
switch语句及循环语句的条件测试部分以及一些简单的关系表达式中。
4.1.3、void
longjmp(jmp_buf env, int val):用于恢复由最近一次调用setjmp()时保存到env的状态信息。当它执行完时,程序执行流会跳转到setjmp()那行,并根据重新执行setjmp(),但此时的setjmp()得到的返回值是val。
/*************** 除法操作异常处理优化 ************/
#include <iostream>
#include <csetjmp> //for setjmp, longjmp();
using namespace std;
static jmp_buf env; //须定义全局的上下文环境。 static避免别的文件使用。作用域限定符号(修饰全局变量时,就是这个作用)
double divide(double a, double b)
{
const double delta = 0.0000000000000000001;
double ret = 0;
if(!( (-delta < b) && (b < delta) ))
{
ret = a/b;
}
else
{
longjmp(env, 1); //当错误发生时会跳转到setjmp那里的代码处,重新执行setjmp并把其的返回值设置为1.。
}
return ret;
}
//分析函数时先从main函数分析,
int main()
{
if(setjmp(env) == 0)//先保存上下文环境,直接调用时返回值为0,通过longjmp调用,返回值为非0; 这种结构破坏了三大执行结构。
{
double r = divide(1, 0);
cout << "r = " << r << endl;
}
else
{
cout << "Divide by Zero....." << endl;
}
return 0;
}
4.2、缺陷
4.2.1、引入setjmp()和longjmp()必然涉及到使用全局变量
4.2.2、暴力跳转导致代码可读性降低
4.2.3、本质还是if-else异常处理方式
5、C语言异常处理存在的通病
5.1、会使程序逻辑中混入大量的处理异常的代码5.2、正常逻辑和异常处理代码混合在一起,导致代码迅速膨胀,难以维护。
/************ 异常处理代码分析 ************/
#include <iostream>
using namespace std;
#define SUCCESS 0
#define INVALID_POINTER -1
#define INVALID_LENGTH -2
#define INVALID_PARAMETER -3
int MemSet(void* dest, unsigned int length, unsigned char v)
{
if(dest == NULL)
{
return INVALID_POINTER;
}
if (length < 4)
{
return INVALID_LENGTH;
}
if( (v < 0) || (v > 9) )
{
return INVALID_PARAMETER;
}
unsigned char* p = (unsigned char*)dest;
for(int i = 0; i< length; i++)
{
//将char赋值给int。
//1.如果是char,则最高位为符号位,char赋值给int时会扩展最高位
//2.如果是unsigned,则不会扩展,即低8位为char的值,其余24位为0
p[i] = v;
}
return SUCCESS;
}
int main()
{
int ai[15];
int ret = MemSet(ai, sizeof(ai),0);
//正常处理与异常处理的代码混杂,不容易看出哪些是正常处理时的代码
//哪些是异常发生时应处理的代码(特别是当返回值用数字表示,而不是这里有意义的常量名时)
if(ret == SUCCESS)
{
}
else if(ret == INVALID_POINTER)
{
}
else if(ret == INVALID_LENGTH)
{
}
else if(ret == INVALID_PARAMETER)
{
}
return 0;
}
6、小结
6.1、程序中不可避免的会发生异常6.2、异常是在开发阶段就可以预见的运行时问题
6.3、C语言中通过经典的if-else
6.4、C++中存在更好的异常处理方式
相关文章推荐
- 第63课-C语言异常处理
- C语言中的异常处理
- 异常处理---C语言
- C语言异常处理的方式
- C语言的setjmp:异常处理与构建协作式多任务系统
- C语言异常处理机制——为您的C程序添加异常处理
- android studio ndk开发中c语言中异常处理
- C语言异常处理之setjmp、longjmp的一个小例程
- C语言异常处理和结构化异常处理有什么区别?
- C语言中的异常处理
- 全面了解setjmp与longjmp(C语言异常处理机制)
- C语言中利用setjmp和longjmp做异常处理
- C语言异常处理机制
- C语言中处理异常中断的方法
- atitit.面向过程的编程语言异常处理 c语言 asp vbs 的try catch 实现
- C语言中的异常处理机制
- 从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介
- c语言中的异常处理,setjmp 与 longjmp函数
- 第六十三课、C语言的异常处理
- 神奇的C语言五:异常处理