人的一生会遇到很多大起大落,尤其是程序员.

  程序员写好的程序,论其消亡形式无非三种:无疾而终、自杀、他杀.

  当然作为一名程序员,最乐意看到自己写的程序能够无疾而终,因此尽快的学习异常处理机制是非常重要的!

  使自己的程序在遇到错误时能够克服错误,更健壮,而不是遇到错误就愤愤自杀.

  因此,在简述C++的异常机制之前,本文先来简述一下C语言中的异常处理机制.

  在C语言中,传统的错误处理方式有如下几种:

1.直接终止程序(自杀)

  例如:

int main(){
int a = 10;
int b = 20;
int c = a/0;
return 0;
}

  当用gcc编译完后,执行,会打印“浮点数例外”,然后程序结束.

  这种情况是不允许的,无条件终止程序的库无法运用到不能当机的程序里。

2.返回一个错误的值,附加错误码

  这种错误处理方式也很常见,比如我们用C语言打开一个文件失败时:

#include<stdio.h>
#include<errno.h>
int main(){
FILE* fp = fopen("test.txt","r");
if(NULL == fp){
printf("文件打开失败,错误码:%d\n",errno);
}
return 0;
}

  因为我当前处于Linux系统下,没有GetLastError()函数,所以在Linux下使用全局变量errno来演示.

  这种情况,比较常用,但是有时不合适,例如返回错误码是int,每个调用都要检查错误值,极不方便,也容易让程序规模加倍

3.返回一个合法的值,让程序处于某种非法的状态

  这种例子,最常见的就是atoi函数,例如:

#include<stdio.h>
#include<stdlib.h>
int main(){
int a = atoi("123456789");
int b = atoi("dasdasdcs");
printf("a = %d\n",a);
printf("b = %d\n",b);
return 0;
}

  虽然b为0,但是有一个全局变量表示了这个0属于非法值,不是由字符串0转过来的.

  这种情况,很容易误导调用者,万一调用者没有去检查全局变量errno或者通过其他方式检查错误,那是一个灾难,而且这种方式在并发的情况下不能很好工作

4.调用一个预先准备好在出现"错误"的情况下使用的函数.

  这种异常处理情况比较少见,那我就现场直编了一个:

#include<stdio.h>
#include<stdlib.h>
void DealError(){
printf("除数为0,老兄你在逗我?\n");
}
typedef void(*fun)();
int Div(int a,int b,fun callback){
if(b==0){
callback();
return 0;
}
return a/b;
} int main(){
printf("正常情况下的4/2 = %d\n",Div(4,2,DealError));
printf("调用错误处理函数的4/0 = %d\n",Div(4,0,DealError));
return 0;
}

5、通过暴力的方式解决

  暴力的方式有两种,abort()函数和常见exit()函数.例如依然处理除0问题,代码可以这样写:

#include<stdio.h>
#include<stdlib.h>
int Div(int a,int b){
if(b==0){
//exit(1); //直接退出
abort(); //在Windows下会弹出一个信息框
}
return a/b;
} int main(){
printf("正常情况下的4/2 = %d\n",Div(4,2));
printf("调用错误处理函数的4/0 = %d\n",Div(4,0));
return 0;
}

6、使用goto语句

  虽然,goto语句十分强大,但违背了程序的顺序执行,打乱的程序的执行流,盲目的使用goto语句可能会出现意想不到的错误,因此,并不推荐使用goto语句.

  但,尽管如此,为了探索C语言的异常处理机制,我还是实现一下goto语句处理异常的代码.

#include<stdio.h>
#include<stdlib.h>
int main(){
int a = 0;
int b = 0;
printf("请输入两个值:\n");
printf("a = ");
scanf("%d",&a);
printf("b = ");
scanf("%d",&b);
if(b==0){
goto Error;
}
printf("a/b = %d\n",a/b);
return 0;
Error:
printf("除数不能为0,程序异常退出!\n");
exit(-1);
}

7、使用setjmp()与longjmp()

  goto语句虽然可以跳来跳去,但标记与goto必须处于同一作用域内.

  想从一个函数跳转到另一个函数,就必须使用setjmp与longjmp组合.

  实例如下:

#include<stdio.h>
#include<setjmp.h> jmp_buf mark; int Div(int a,int b){
if(b==0){
longjmp(mark,1);  //会使state = 1
}
return a/b;
}
int main(){
int State = setjmp(mark); //保存寄存器相关信息,初始值为0
if(State==0){
Div(4,0);
}else{
switch(State){
case 1:
printf("除0异常!\n");
}
}
return 0;
}

注意事项:

  1、setjmp必须先调用,在异常位置通过调用longjmp以恢复先前被保存的程序执行点,否则将导致 不可预测的结果,甚至程序崩溃。

  2、在调用setjmp的函数返回之前调动longjmp,否则结果不可预料。

setjmp与longjmp存在以下缺陷:

  1、函数的使用者必须非常靠近函数调用的地方编写错误处理代码,无疑使代码变的臃肿笨拙。

  2、setjmp()和longjmp()并不能够很好的支持C++面向对象的语义。

  以上情况,便是C语言中的异常处理常见的机制,C++提供了更为完善的异常处理机制,我将在下文中简述.

【C++】异常简述(一):C语言中的异常处理机制的更多相关文章

  1. C语言中的异常处理机制

    #define try if(!setjmp(Jump_Buffer)) 返回try现场后重新执行判断,所以有两次执行. http://blog.csdn.net/tian_dao_chou_qin/ ...

  2. Java语言中的异常处理

    Java语言中的异常处理包括声明异常.抛出异常.捕获异常和处理异常四个环节.   throw用于抛出异常.   throws关键字可以在方法上声明该方法要抛出的异常,然后在方法内部通过throw抛出异 ...

  3. C语言中的异常处理

    一 前言: 异常处理,对于做面向对象开发的开发者来说是再熟悉不过了,例如在C#中有 try { ... } catch( Exception e){...} finally{ ..... } 在C++ ...

  4. .NET中的异常处理机制(一)

    1.异常处理的总体指导思想 学习C#中的异常处理机制,大概要了解以下几点: 首先,我们需要知道的事所有具体异常都是继承自System.Exception基类的. 其次,要熟悉FCL类库内置好的一些异常 ...

  5. 深入理解C++中的异常处理机制

    异常处理 增强错误恢复能力是提高代码健壮性的最有力的途径之一,C语言中采用的错误处理方法被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编 写错误处理代码,这样会使得其变得笨拙和难以使用.C ...

  6. Java中的异常处理机制《》

    异常机制已经成为判断一门编程语言是否成熟的标准,异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性. Java异常机制主要依赖于try.catch.finall ...

  7. C++中的异常处理机制

    C++中的捕获异常机制catch参数中实参的类型不同,采取的处理方式则不相同,且与普通的函数调用还不一样,具体表现为当抛出异常throw A()或throw obj时,对象会进行一次额外的对象复制操作 ...

  8. 16、java中的异常处理机制

    异常:就是程序在运行时出现不正常情况.异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述.并封装成对象. 其实就是java对不正常情况进行描述后的对象体现. 对于问题的划 ...

  9. Java中的异常处理机制的简单原理和应用

    异常是指java程序运行时(非编译)所发生的非正常情况或错误,与现实生活中的事件很相似,现实生活中的事件可以包含事件发生的时间.地点.人物.情节等信息,可以用一个对象来表示,Java使用面向对象的方式 ...

随机推荐

  1. 大学生程序设计邀请赛(华东师范大学)B. 分词 DP

    B. 分词   有一句句子因为粘贴的时候出现了一点问题空格全部丢失了.现在给一本字典,每个词都对应这个词出现的频率(每十亿).根据这个频率,我们可以根据下面的公式算出这个词带来的收益 P(word): ...

  2. HOSVD高阶奇异值分解

    高阶奇异值分解(High Order Singular Value  Decomposition,   HOSVD) 奇异值分解SVD(Singular Value Decomposition)是线性 ...

  3. list if else 遍历 特征合并

    特征合并 import re l = ['a', 'b1'] ll = [i if re.search('\d', i) is None else i[0:re.search('\d', i).end ...

  4. ios移动端浏览器点击事件失效的解决方案

    点击事件失效的原因可能是因为,你用了事件代理了, 比如这样 $(document).on("click",".fd",function(){ }) 这段代码在安 ...

  5. 一步一步学Silverlight 2系列(5):实现简单的拖放功能

    述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...

  6. C#函数3递归

    using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace Console ...

  7. Ural2089:Experienced coach(二分图匹配)

    Misha trains several ACM teams at the university. He is an experienced coach, and he does not undere ...

  8. 使用Django.core.cache操作Memcached导致性能不稳定的分析过程

    使用Django.core.cache操作Memcached导致性能不稳定的分析过程 最近测试一项目,用到了Nginx缓存服务,那可真是快啊!2Gb带宽都轻易耗尽. 不过Api接口无法简单使用Ngin ...

  9. Tensorflow卷积接口总结

    tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None) 这个接口用了这么久,每次都有点迷惑,这里 ...

  10. 【179】IDL 读写 NetCDF 文件

    NetCDF(network Common Data Form)由位于科罗拉多州波尔市的 Unidata 程序中心开发,主要应用于大气科学的研究.NetCDF 的数据模式具有简单性和灵活性的特点.Ne ...