C语言异常处理的方式

1、语言本身没有异常处理的原则。

一、异常的概念:

1、程序在运行过程中可能产生异常。

2、异常(Exception)与Bug的区别

@1:异常是程序运行时可预料的执行分支。是我们在程序开发时要考虑的一些特殊情况

@2:Bug是程序中的错误,是不可被预期的运行方式

二、异常(Exception)和Bug的对比

1、异常的例子:

(1)运行时产生除0的情况

(2)需要打开的外部文件不存在

(3)数组访问越界

2、bug的例子:

(1)使用了野指针

(2)堆数组使用结束后未释放

(3)选择排序无法处理长度为0的数组

三、C语言经典处理异常的方式:if...else...

1、

void func(...)

{

if (判断是否产生异常)

{

正常情况的代码逻辑;

}

else

{

异常情况代码逻辑;

}

}

四、编程实践一下异常处理

1、在C语言中,除法操作异常处理(除数为0的情况),不是完美的方法

例:

#include <stdio.h>

/*

* C语言中对除数为0情况下的异常处理方法,不是完美的方法

*

*/

static double divide(double a, double b, int *valid) //用valid表示异常是否发生,1为没发生、0为发生

{

const double delta = 0.000000000001;

double ret = 0;

if (!((-b < delta) && (b < delta)))

{

*valid = 1;

ret = a / b;

}

else

{

*valid = 0;

}

return ret;

}

inline static int char_to_num(const char c)

{

return (c - 48);

}

int main(int argc, char *argv[])

{

int valid = 0;

double r = 0;

#if 0

if (2 == argc)

{

printf("argc = %d. argv[1][0] = %d.\n", argc, argv[1][0]);

}

#endif

r = divide(char_to_num(argv[1][0]), char_to_num(argv[1][1]), &valid);

if (valid)

{

printf("r = %f.\n", r);

}

else

{

printf("Divide operator error, by zero.\n");

}

// printf("char_to_num(%c) = %d.\n", ‘1‘, char_to_num(‘9‘) );

return 0;

}

2、上面例子处理除数为0的异常情况的缺陷:

(1)divide函数有三个参数,难以理解其用法

(2)divide函数调用后必须判断valid代表的结果

@1:当vaild为true时,运算结果正常

@2:当vaild为false时,运算过程出现异常

3、所以我们要将上面的divide函数的缺陷弥补起来,使其只有两个参数,用起来方便。

(1)C语言提供了两个函数:setjmp()和longjmp()进行优化。但是这两个函数不要随意的调用,因为这两个函数简单出爆,将破坏结构化程序设计的特性

在<csetjmp>头文件中

@1:

int setjmp(jmp_buf env)

:将当前上下文保存在jmp_buf结构体中

@2:

void longjmp(jmp_buf env, int val)

:从jmp_buf结构体中恢复setjmp()保存的上下文

:最终从setjmp函数调用点返回,返回值为val

(2)利用setjmp()和longjmp()函数来节省divide函数对除数为0情况时的异常处理,但这个方法也不好。

例:

#include <stdio.h>

#include <setjmp.h>

/*

* C语言中对除数为0情况下的异常处理方法,这个方法也不好,还不如用三个参数的divide解决

*

*/

static jmp_buf jmpbuff;

static double divide(double a, double b) //用valid表示异常是否发生,1为没发生、0为发生

{

const double delta = 0.000000000001;

double ret = 0;

if (!((-b < delta) && (b < delta)))

{

ret = a / b;

}

else

{

longjmp(jmpbuff, 1); //代码如果执行到这里,调用这个函数时,会跳转到setjmp这个函数调用的位置,并且这时setjmp函数的返回值为这个longjmp函数的第二个参数值

}

return ret;

}

inline static int char_to_num(const char c)

{

return (c - 48);

}

int main(int argc, char *argv[])

{

#if 0

if (2 == argc)

{

printf("argc = %d. argv[1][0] = %d.\n", argc, argv[1][0]);

}

#endif

if (setjmp(jmpbuff) == 0)

{

printf("num = %f.\n", divide((double)char_to_num(argv[1][0]), (double)char_to_num(argv[1][1])));

}

else

{

printf("Divide operator error, by zero.\n");

}

// printf("char_to_num(%c) = %d.\n", ‘1‘, char_to_num(‘9‘) );

return 0;

}

(3)使用setjmp()和longjmp()的缺陷

@1:必然涉及到使用一个jmp_buf类型的全局变量

@2:暴力跳转导致代码可读性降低。

@3:本质还是if...else...异常处理方式,C语言中处理异常方式的经典方法。

(3)C语言中的经典异常处理方式会使得程序逻辑中混入大量的处理异常的代码, 正常逻辑代码和异常处理代码混合在一起,导致代码迅速膨胀,难以维护。

4、C++中有没有更好的异常处理方式呢?

(1)答案是有的,C++语言中已经将直接将异常的概念内置于语法当中了。可以通过关键字就可以看出来哪些代码是处理正常功能的代码,哪些代码是进行异常处理的代码。

时间: 2024-10-13 07:50:08

C语言异常处理的方式的相关文章

第63课 C语言异常处理

1. 异常的概念 (1)程序在运行过程中可能产生异常 (2)异常(Exception)与Bug的区别 ①异常是程序运行时可预料的执行分支 ②Bug是程序是的错误,是不被预期的运行方式 2. 异常和Bug的对比 (1)异常:如运行时产生除0的情况.需要打开的外部文件不存在.数组访问时越界 (2)Bug:如使用野指针.堆数组使用结束后未释放.选择排序无法处理长度为0的数组 3. C语言经典处理方式:if-else (1)示例程序 void func(…) { if(判断是否产生异常) { 正常情况代

C 语言异常处理(五十二)

我们今天来看下异常处理,在看 C++ 的异常处理之前,先来看看 C 语言中的异常处理.那么什么是异常呢?在程序运行过程中可能会产生异常,异常(Exception)与 Bug 的区别是:异常是程序运行时可预料的执行分支,而 Bug 是程序中的错误,是不被预期的运行方式. 下来我们来看看异常和 Bug 的对比:a> 异常比如运行时产生除 0 的情况,需要打开的外部文件不存在,数组访问时越界:b> Bug 是使用野指针,堆数组使用结束后未释放,选择排序无法处理长度为 0 的数组.在 C 语言中的经典

R语言读写中文编码方式

最近遇到一个很头疼的事,就是 R语言读写中文编码方式.在网上找到了一篇博文,谢谢博主的精彩分享,让我很快解决了问题,在此也分享一下 R语言读写数据的方法很多,这里主要是我在使用read.csv/read.table和write.csv/write.table时遇到的一些中文格式编码的问题.常见的中文编码方式两种:GBK(GB2312)和UTF-8.     Windows系统下: read.csv()和read.table()方法不指定文件格式时,默认读取的文件是GBK格式.Rstudio里面有

R语言两种方式求指定日期所在月的天数

             R语言两种方式求指定日期所在月的天数 days_monthday<-function(date){ m<-format(date,format="%m") days31<-c("01","03","05","07","08","10","12") days30<-c("04",&

TPL - Part 2 异常处理常用方式

异常处理常用方式 Task task1 = new Task(() => { ArgumentOutOfRangeException exception = new ArgumentOutOfRangeException(); exception.Source= "task1"; throw exception; }); Task task2 = new Task(() => { throw new NullReferenceException(); }); Task ta

C语言 数据存储方式

C语言 数据存储方式 一.源码 一个数的原码(原始的二进制码)有如下特点: 最高位做为符号位,0表示正,为1表示负 其它数值部分就是数值本身绝对值的二进制数 负数的原码是在其绝对值的基础上,最高位变为1 下面数值以1字节的大小描述: 十进制数 原码 +15 0000 1111 -15 1000 1111 +0 0000 0000 -0 1000 0000 注:原码表示法简单易懂,与带符号数本身转换方便,只要符号还原即可,但当两个正数相减或不同符号数相加时,必须比较两个数哪个绝对值大,才能决定谁减

Go语言之Go语言 异常处理与测试

Go 语言异常处理与测试 Go 语言异常处理 Go语言没有结构化异常,使用 panic 抛出错误,recover 捕获错误. 异常的使用场景简单描述:Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理. panic: 1.内置函数 2.假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行 3.返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,假如

c语言异常处理机制

异常处理机制:setjmp()函数与longjmp()函数 C标准库提供两个特殊的函数:setjmp() 及 longjmp(),这两个函数是结构化异常的基础,正是利用这两个函数的特性来实现异常. 所以,异常的处理过程可以描述为这样: 首先设置一个跳转点(setjmp() 函数可以实现这一功能),然后在其后的代码中任意地方调用 longjmp() 跳转回这个跳转点上,以此来实现当发生异常时,转到处理异常的程序上,在其后的介绍中将介绍如何实现. setjmp() 为跳转返回保存现场并为异常提供处理

4 C 语言 数值存储方式 数组

源码 补码 反码 数组定义,初始化,使用,随机数 找最大数,逆置,冒泡排序, scanf 输入字符串 字符串处理 字符串溢出等问题 scanf() gets() puts() fputs() strlen() strcat() strncat() strcmp() strncmp() strchr() strstr() strtok() atoi() atof() atol() C 字符串数组 定义数组 遍历输出数组每个元素的值 //GCC 编译方式: C:\MinGW\project>gcc