C中的异常处理
1,C 语言崇尚简洁高效,因此语言本身并没有异常处理的相关语法规则,但是异常处理在 C 语言中 是存在的,我们有必要从 C 语言开始先看一看 C 语言中的异常处理是怎样, 然后对比 C++ 里面的异常处理是怎样;
2,异常的概念:
1,程序在运行过程中可能产生异常;
1,异常是我们在程序开发中必须考虑的一些特殊情况;
2,异常(Exception)与 Bug 的区别:
1,异常是程序运行时可预料的执行分支;
1,例如计算器相关的程序,涉及到除法操作的时候,就应该全面的想想有没有会产生意外的情况,比如除数为 0,这是一种意外情况,但是我们已经预料到这种意外情况,并且这种意外情况在计算器相关的程序里面是不可避免的,因此我们在做开发的时候,就必须有一些代码来处理这样的情况,这些代码就叫做异常处理的代码,而异常是程序运行时可以预料的情况(这就是异常和 Bug 的区别);
2,Bug 是程序中的错误,是不被预期的运行方式;
3,异常和 Bug 的对比:
1,异常:
1,运行时产生除 0 的情况;
2,需要打开的外部文件不存在;
3,数组访问的越界;
2,Bug:
1,使用野指针;
2,堆数组使用结束后未释放;
1,内存泄漏一定是 Bug;
3,选择排序无法处理长度为 0 的数组;
4,异常处理的方式:
1,C 语言经典处理方式:if ... else ...
1,代码示例:
void func(...)
{
if( 判断是否产生异常 )
{
// 正常情况代码逻辑;
}
else
{
// 异常情况代码逻辑;
}
}
2,除法操作异常处理编程实验:
#include <iostream>
#include <string> using namespace std; double divide(double a, double b, int* valid)
{
const double delta = 0.000000000000001;
double ret = ; if( !((-delta < b) && (b < delta)) )
{
ret = a / b; *valid = ; // 为了处理除数为 0 和本身结果就是 0 之间的区别;
}
else
{
*valid = ; // 异常了;
} return ret;
} int main(int argc, char *argv[])
{
int valid = ;
double r = divide(, , &valid); if( valid )
{
cout << "r = " << r << endl;
}
else
{
cout << "Divided by zero..." << endl;
} return ;
}
1,工程上 if 处理正常分支,else 处理异常分支;
2,除法操作需要三个参数,而加减乘法都只要两个参数,这样不优雅;
3,如果第三个参数没有指向合法的对象(NULL),就会出现段错误;
3,缺陷:
1,divide 函数有 3 个参数,难以理解其用法;
1,降低了代码的可读性,后期的维护成本就会增加;
2,改进的方向就是统一除法和加减乘法的调用方式,将三个参数改变为两个参数,并且还有异常处理的代码;
2,divide 函数调用后必须判断 valid 代表的结果;
1,当 valid 为 true 时,运行结果正常;
2,当 valid 为 false 时,运行过程出现异常;
4,通过 setjmp() 和 longjmp() 进行优化:
1,int setjmp(jmp_buf env)
1,将当前上下文保存在 jmp_buf 结构体中;
2,jmp_buf 一般的是全局变量;
2,void longjmp(jmp_buf env, int val)
1,从 jmp_buf 结构体中恢复 setjmp() 保存的上下文;
2,最终从 setjmp 函数调用点返回,返回值为 val;
3,这两个函数不要随便调用,因为它们简单粗暴,它们将破坏结构化程序设计的特性,结构化程序设计三大特性有顺序执行、循环执行、分支执行,如果调用这两个函数,将会有其他的执行方式出来;
5,除法操作异常处理优化编程实验:
#include <iostream>
#include <string>
#include <csetjmp> using namespace std; static jmp_buf env; // 保存程序执行的上下文; double divide(double a, double b)
{
const double delta = 0.000000000000001;
double ret = ; if( !((-delta < b) && (b < delta)) )
{
ret = a / b;
}
else
{
longjmp(env, ); // 当 b = 0 时,跳转回 env 这个全局变量所保存的程序上下文的地方,也就是 main() 中的 if() 语句;此时 divide() 程序的执行立即停止,并从 setjmp() 函数返回,返回值为 longjmp() 中的参数 1;
} return ret;
} int main(int argc, char *argv[])
{
if( setjmp(env) == ) //调用 setjmp(env) 将程序的上下文保存在 env 里面;
{
double r = divide(, ); // Divided by zero...;
double r = divide(, ); // 1; cout << "r = " << r << endl;
}
else
{
cout << "Divided by zero..." << endl;
} return ;
}
1,程序执行过程:
1,首先执行到 main() 中的 if() 语句;
2,直接调用 setjmp(),这个函数内部就会将当前程序执行的上下文全部保存在这个全局变量里面,因为是直接调用的,所以保存完了返回值就是 0;
3,运行到 divide() 后,判断到 b 为 0,则执行 longjum(),它根据 env 这个全局变量里面保存的信息来恢复之前的程序上下文;
4,之前的程序上下文是在 if() 中调用 setjmp() 保存的,所以说 longjmp() 函数一旦被调用,则 divide() 函数立即停止,出口在 setjmp(),此时返回值是 longjmp() 中第二个参数 1;
5,执行到 if...else 语句的 else 语句中;
2,这两个函数配合起来破坏了结构化程序设计的三大特性,所以简单的程序理解起来很复杂;
3,优雅但理解难,工程应用不多,工程中推荐使用第一种异常处理方式;
6,改进后缺陷:
1,setjmp() 和 longjmp() 的引入:
1,必然涉及到使用全局变量;
2,暴力跳转导致代码可读性降低;
3,本质还是 if ... else ... 异常处理方式;
7,C 语言中的经典异常处理方式问题:
1,会使得编程中逻辑中混入大量的处理异常代码;
2,正常逻辑代码和异常处理代码混合在一起,导致代码迅速膨胀,难以维护;
1,工程中约定,if 处理正常情况,else 处理异常情况,好歹代码中能够看出正常异常处理代码放在什么地方;
5,异常处理代码分析实例分析:
#include <iostream>
#include <string> 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 < )
{
return INVALID_LENGTH;
} if( (v < ) || (v > ) )
{
return INVALID_PARAMETER;
} unsigned char* p = (unsigned char*)dest; for(int i=; i<length; i++)
{
p[i] = v;
} return SUCCESS;
} int main(int argc, char *argv[])
{
int ai[];
int ret = MemSet(ai, sizeof(ai), ); if( ret == SUCCESS ) // 处理异常代码逻辑;
{
}
else if( ret == INVALID_POINTER ) // 三个地方处理异常代码逻辑;
{
}
else if( ret == INVALID_LENGTH )
{
}
else if( ret == INVALID_PARAMETER )
{
} return ret;
}
1,这对于职场新人很痛苦,因为代码逻辑的模块不清晰;
6,C++ 中有没有更好的异常处理方式?
1,直接通过关键字知道哪些代码处理正常情况的代码,哪些是异常情况的代码;
7,小结:
1,程序中不可避免的会发生异常;
2,异常是在开发阶段就可以预见的运行时问题;
3,C 语言中通过经典的 if ... else ... 方式处理异常;
4,C++ 中存在更好的异常处理方式;
C中的异常处理的更多相关文章
- 【repost】JS中的异常处理方法分享
我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...
- 第65课 C++中的异常处理(下)
1. C++中的异常处理 (1)catch语句块可以抛出异常 ①catch中获捕的异常可以被重新抛出 ②抛出的异常需要外层的try-catch块来捕获 ③catch(…)块中抛异常的方法是throw; ...
- Swift基础--Swift中的异常处理
Swift中的异常处理 OC中的异常处理:方法的参数要求传入一个error指针地址,方法执行完后,如果有错误,内部会给error赋值 Swift中的异常处理:有throws的方法,就要try起来,然后 ...
- ASP.NET Web API 中的异常处理(转载)
转载地址:ASP.NET Web API 中的异常处理
- Struts2中的异常处理
因为在Action的execute方法声明时就抛出了Exception异常,所以我们无需再execute方法中捕捉异常,仅需在struts.xml 中配置异常处理. 为了使用Struts2的异常处理机 ...
- C++中的异常处理(三)
C++中的异常处理(三) 标签: c++C++异常处理 2012-11-24 23:00 1520人阅读 评论(0) 收藏 举报 分类: 编程常识(2) 版权声明:本文为博主原创文章,未经博主允许 ...
- C++中的异常处理(二)
C++中的异常处理(二) 标签: c++C++异常处理 2012-11-24 20:56 1713人阅读 评论(2) 收藏 举报 分类: C++编程语言(24) 版权声明:本文为博主原创文章,未经 ...
- C++中的异常处理(一)
来自:CSDN 卡尔 后续有C++中的异常处理(二)和C++中的异常处理(三),C++中的异常处理(二)是对动态分配内存后内部发生错误情况的处理方法,C++中的异常处理(三)中是使用时的异常说明. ...
- Java中实现异常处理的基础知识
Java中实现异常处理的基础知识 异常 (Exception):发生于程序执行期间,表明出现了一个非法的运行状况.许多JDK中的方法在检测到非法情况时,都会抛出一个异常对象. 例如:数组越界和被0除. ...
- java 中的异常处理
一. 异常的概念和Java异常体系结构 异常是程序运行过程中出现的错误.本文主要讲授的是Java语言的异常处理.Java语言的异常处理框架, 是Java语言健壮性的一个重要体现. Java把 ...
随机推荐
- jquery dblclick()方法 语法
jquery dblclick()方法 语法 作用:当双击元素时,会发生 dblclick 事件.当鼠标指针停留在元素上方,然后按下并松开鼠标左键时,就会发生一次 click.在很短的时间内发生两次 ...
- Python Internet 模块
Python Internet 模块 以下列出了 Python 网络编程的一些重要模块: 协议 功能用处 端口号 Python 模块 HTTP 网页访问 80 httplib, urllib, xml ...
- Eclipse中文件结构的树形显示问题
问题描述:在Eclipse中的SpringBoot文件显示层级消失. 这种情况下编辑代码的效率大大下降. 原因:Eclipse的工作模式不正确.上面的工作模式是Java模式.实际上应采用JavaEE模 ...
- codevs 5969 [AK]刻录光盘x
题目描述 Description • 在FJOI2010夏令营快要结束的时候,很多营员提出来要把整个夏令营期间的资料刻录成一张光盘给大家,以便大家回去后继续学 ...
- c++复习——一个小疑问
C++中,子类为什么不能访问基类的private数据? emmm 来自一个vegetable dog的疑问: 首先基类可以通过调用自身public成员函数来访问private 而子类又可 ...
- pycharm安装与永久激活
1.Pycham下载 https://www.jetbrains.com/pycharm/download/#section=windows 直接下载专业版 2.安装 这里就不必细说,直接next就O ...
- HDU 6155 Subsequence Count (DP、线性代数、线段树)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6155 题解 DP+线代好题.(考场上过多时间刚前两题,没怎么想这题--) 首先列出一个DP式: 设\( ...
- 使用layui异步请求上传图片在tp5.1环境下出现“请对上传接口返回json”的错误的解决方法
正常情况下返回json数据使用return json(); 但是使用layui会报错,然后想到了使用json_encode()包装一下用一个变量接收后,再使用return();返回接收json格式的变 ...
- 190707Python-MySQL
一.Python连接MySQL import pymysql conn = pymysql.connect(host='192.168.100.4', port=3306, user='dongfei ...
- JVM系列2:HotSpot虚拟机对象
1.对象创建过程: ①.类加载检查:当java虚拟机遇到一条new指令时,首先会去检查该指令的参数能否在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析.初始化过,如果没 ...