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中的异常处理的更多相关文章

  1. 【repost】JS中的异常处理方法分享

    我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...

  2. 第65课 C++中的异常处理(下)

    1. C++中的异常处理 (1)catch语句块可以抛出异常 ①catch中获捕的异常可以被重新抛出 ②抛出的异常需要外层的try-catch块来捕获 ③catch(…)块中抛异常的方法是throw; ...

  3. Swift基础--Swift中的异常处理

    Swift中的异常处理 OC中的异常处理:方法的参数要求传入一个error指针地址,方法执行完后,如果有错误,内部会给error赋值 Swift中的异常处理:有throws的方法,就要try起来,然后 ...

  4. ASP.NET Web API 中的异常处理(转载)

    转载地址:ASP.NET Web API 中的异常处理

  5. Struts2中的异常处理

    因为在Action的execute方法声明时就抛出了Exception异常,所以我们无需再execute方法中捕捉异常,仅需在struts.xml 中配置异常处理. 为了使用Struts2的异常处理机 ...

  6. C++中的异常处理(三)

    C++中的异常处理(三) 标签: c++C++异常处理 2012-11-24 23:00 1520人阅读 评论(0) 收藏 举报  分类: 编程常识(2)  版权声明:本文为博主原创文章,未经博主允许 ...

  7. C++中的异常处理(二)

    C++中的异常处理(二) 标签: c++C++异常处理 2012-11-24 20:56 1713人阅读 评论(2) 收藏 举报  分类: C++编程语言(24)  版权声明:本文为博主原创文章,未经 ...

  8. C++中的异常处理(一)

     来自:CSDN 卡尔  后续有C++中的异常处理(二)和C++中的异常处理(三),C++中的异常处理(二)是对动态分配内存后内部发生错误情况的处理方法,C++中的异常处理(三)中是使用时的异常说明. ...

  9. Java中实现异常处理的基础知识

    Java中实现异常处理的基础知识 异常 (Exception):发生于程序执行期间,表明出现了一个非法的运行状况.许多JDK中的方法在检测到非法情况时,都会抛出一个异常对象. 例如:数组越界和被0除. ...

  10. java 中的异常处理

    一. 异常的概念和Java异常体系结构  异常是程序运行过程中出现的错误.本文主要讲授的是Java语言的异常处理.Java语言的异常处理框架,     是Java语言健壮性的一个重要体现. Java把 ...

随机推荐

  1. Linux命令-文本编辑(一)

    Linux命令-文本编辑(一) Linux col命令 Linux col命令用于过滤控制字符. 在许多UNIX说明文件里,都有RLF控制字符.当我们运用shell特殊字符">&quo ...

  2. ZooKeeper 简介说明

    1.什么是Zookeeper? Zookeeper是一个高效的分布式协调服务,它暴露了一些公用服务,比如命名/配置管理/同步控制/群组服务等.我们可以使用Zookeeper来实现比如达成共识/集群管理 ...

  3. 谷歌浏览器安装 socketLog

    第一步(本地浏览器安装调试扩展) 下载扩展包并解压 链接:https://pan.baidu.com/s/14df0ewl_3wjRHc8H1jsrWQ提取码:yyu1 打开谷歌浏览器,地址栏输入 c ...

  4. Java基础__Java中常用数学类Math那些事

     测试 package Cynical_Gary; public class Cynical_Text { public static void main(String[] args){ System ...

  5. Nginx配置记录【例3】

    C服务器,例: [root@82_www_db_2 conf.d]# egrep -v "^#|^$" /etc/nginx/nginx.conf user nginx; work ...

  6. 数据重塑图解—Pivot, Pivot-Table, Stack and Unstack

    Pivot pivot函数用于创建一个新的派生表,该函数有三个参数:index, columns和values.你需要在原始表中指定这三个参数所对定的列名,接下来pivot函数会创建一个新的表格,其中 ...

  7. 分布式-信息方式-ActiveMQ构建应用

                                                     ActivemQ构建应用Broker:相当于一个 ActiveMQ服务器实例命令行启动参数示例如下:1 ...

  8. vue-cli构建一个工程

    使用前,必须要先按照 node:安装node Vue CLI官方文档:https://cli.vuejs.org/zh/ 安装node地址:https://nodejs.org/zh-cn/downl ...

  9. 【Spark机器学习速成宝典】模型篇06随机森林【Random Forests】(Python版)

    目录 随机森林原理 随机森林代码(Spark Python) 随机森林原理 参考:http://www.cnblogs.com/itmorn/p/8269334.html 返回目录 随机森林代码(Sp ...

  10. android 播放音乐媒体文件(三)

    看段小代码: mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mMediaPlayer.setDataSource(url);mM ...