C语言异常处理
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
其中的各个整数值都有一个相应的宏定义,表示不同的异常原因:
代码
这里我们就不以前面的除数为 0 的例子来进行异常处理了,因为我不知道如何定义 自己特定错误的 errno,如果哪位知道,希望能给出方法。我以一个网上的例子来 说明它的使用方法:
代码
这里试图打开一个 d 盘的文件,如果文件不存在,这是查看 errno 的值,结果是 2、 当文件存在时,errno 的值为初始值 0。然后查看值为 2 的错误信息,在宏定义那边 #define ENOFILE 2 /* No such file or directory */ 便知道错误的原因了。 4.使用 goto 语句进行异常处理: goto 语句相信大家都很熟悉,是一个跳转语句,我们还是以除数为 0 的例子,来构 造一个异常处理的例子:
#include <stdio.h> #include <setjmp.h> jmp_buf j; void Exception(void) {
longjmp(j,1); }
double diva(double num1,double num2) {
double re; re=num1/num2;
11 scanf("%lf",&a); 12 printf("请输入第二个数字:");
13 scanf("%lf",&b);
14 if(0==b)
//如果除数为 0 终止程序 ,并挂接到模拟异常捕获的注册函
数
15 {
16
17 atexit(Exception);
18 exit(EXIT_FAILURE);
19 }
20 result=diva(a,b);
21 printf("相除的结果是: %.2lf\n",result);
22 return 0;
23 }
这里需要注意的是,atexit()函数总是被执行的,就算没有 exit()函数,当程 序结束时也会被执行。并且,可以挂接多个注册函数,按照堆栈结构进行执行。abort ()函数与 exit()函数类似,当出错时,能使得程序正常退出,这里就不多说了。
27 };
28
29 void f()
30 {
31
Stack<string> ss(10);
32
try{
33
ss.push("Quiz");
34
string s = ss.pop();
35
ss.pop();
36
}
37
catch(Stack<string>::Overflow){
38
cerr << "error: stack overflow" << endl;
public:
4
void error(void){
5
cerr << "stack Underflow" << endl;
6
}
7
};
8
class Overflow{
//
9
public:
10
void error(void){
11
cerr << "stack Overflow" << endl;
12
}
13
49
return EXIT_SUCCESS;
50 }
51
52 输出结果:error: stack underflow
53
54
改进,我们的第二个版本如下:
如果将
1 class Underflow{ }; // 下溢
2
class Overflow{ };
// 上溢
3和
4
catch(Stack<string>::Overflow){
1 version 1
2 // From: An Overview of the C++ Programming Language
3
4 #include <cstdlib>
5 #include <iostream>
6 #include <string>
7 using namespace std;
8
9 template<class T>class Stack{
19 printf("相除的结果是: %.2lf\n",result); 20 return 0; 21 }
其中 exit 的定义如下:
_CRTIMP void __cdecl __MINGW_NOTHROW exit (int) __MINGW_ATTRIB_NORETURN; exit 的函数原型:void exit(int)由此,我们也可以知道 EXIT_FAILURE 宏应该是一个 整数,exit()函数的传递参数是两个宏,一个是刚才看到的 EXIT_FAILURE,还有 一个是 EXIT_SUCCESS 从字面就可以看出一个是出错后强制终止程序,而一个是程 序正常结束。他们的定义是:
C++ 下面的程例来自《An Overview of the C++ Programming Language》(5.1 异常和
错误处理) 程序用途:使用 C++的异常机制,报告 stack 的上溢或者下溢。(我适当的把代码补全。)
version 1 演示了基本的异常用法。
从 try 里抛出一个异常(实例或对象),由 catch 里的类接受。
#define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 到此,当出现异常的时候,程序是终止了,但是我们并没有捕获到异常信息,要捕 获异常信息,我们可以使用注册终止函数 atexit(),它的原型是这样的:
int atexit(atexit_t func); 具体看如下程序:
我们就前面的问题,使用 assert 断言进行异常终止操作:构造可能出现出错的断言 表达式:assert(number!=0)这样,当除数为 0 的时候,表达式就为 false,程序 报告错误,并终止执行。
代码如下:
代码
3.使用 errno 全局变量,进行异常处理: errno 全局变量主要在调式中,当系统 API 函数发生异常的时候,将 errno 变量赋予 一个整数值,根据查看这个值来推测出错的原因。
C 语言异常处理。
三 C 语言中的异常处理
在 C 语言中异常处理一般有这么几种方式:
1.使用标准 C 库提供了 abort()和 exit()两个函数,它们可以强行终止程序的运 行,其声明处于<stdlib.h>头文件中。 2.使用 assert(断言)宏调用,位于头文件<assert.h>中,当程序出错时,就会 引发一个 abort()。 3.使用 errno 全局变量,由 C 运行时库函数提供,位于头文件<errno.h>中。 4.使用 goto 语句,当出错时跳转。 5.使用 setjmp,longjmp 进行异常处理。 接下来,我们就依次对这几种方式来看看到底是怎么做的: 我们仍旧以前面处理除数为 0 的异常为例子。 1.使用 exit()函数进行异常终止:
代码
5.使用 setjmp 和 longjmp 进行异常捕获与处理: setjmp 和 longjmp 是非局部跳转,类似 goto 跳转作用,但是 goto 语句具有局限性, 只能在局部进行跳转,当需要跳转到非一个函数内的地方时就需要用到 setjmp 和 longjmp。setjmp 函数用于保存程序的运行时的堆栈环境,接下来的其它地方,你 可以通过调用 longjmp 函数来恢复先前被保存的程序堆栈环境。异常处理基本方法: 使用 setjmp 设置一个跳转点,然后在程序其他地方调用 longjmp 跳转到该点(抛 出异常). 代码如下所示:
return re; }
int main() {
double a,b,result;
//两数相除函数
printf("请输入第一个数字:"); scanf("%lf",&a); printf("请输入第二个数字:"); if(setjmp(j)==0) { scanf("%lf",&b); if(0==b) Exception(); result=diva(a,b);
printf("相除的结果是: %.2lf\n",result); } else printf("试图除以一个为 0 的数字\n");
return 0; }
四 总结:
除了以上几种方法之外,另外还有使用信号量等等方法进行异常处理。当然在实际 开发中每个人都有各种调式的技巧,而且这文章并不是说明异常处理一定要这样做, 这只是对一般做法的一些总结,也不要乱使用异常处理,如果弄的不好就严重影响 了程序的效率和结构,就像设计模式一样,不能胡乱使用。
2.使用 assert()进行异常处理:
assert()是一个调试程序时经常使用的宏,切记,它不是一个函数,在程序运行时它 计算括号内的表达式,如果表达式为 FALSE (0), 程序将报告错误,并终止执行。 如果表达式不为 0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现 了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错 误。 另外需要注意的是:assert 只有在 Debug 版本中才有效,如果编译为 Release 版本 则被忽略。
1 #include <stdio.h>
2 #include <stdlib.h>
3 double diva(double num1,double num2)
4{
5
double re;
6
re=num1/num2;
7
return re;
8}
9 int main()
10 {
11 double a,b,result;
1 #include <stdio.h>
2 #include <stdlib.h> 3 void Exception(void) 捕获异常信息
//注册终止函数,通过挂接到此函数,
4{
5
printf("试图去除以一个为 0 的数字,出现异常!\n");
6}
7 int main()
8{
9 double a,b,result; 10 printf("请输入第一个数字:");
12 printf("请输入第一个数字:");
13 scanf("%lf",&a);
14 printf("请输入第二个数字:");
15 scanf("%lf",&b);
16 if(0==b)
17 exit(EXIT_FAILURE);
18 result=diva(a,b);
//两数相除函数 //如果除数为 0 终止程序
39
}
40
catch(Stack<string>::Underflow){
41
cerr << "error: stack underflow" << endl;
42
}
43 }
44
45 int main(int argc, char *argv[])
46 {
47
f();
48
system("PAUSE");
};
14 和
15
catch(Stack<string>::Overflow& e){
16
e.error();
17
}
18
catch(Stack<string>::Underflow& e){
19
e.error();
20
}
21
改后的程序和原先的区别在哪里,看出来了吗? 呵呵呵。
当然,我们还能将代码改进。这样产生了第三个版本。
18
~Stack(){}
19
void push(T c){
20
if(top == max_size) throw Overflow();
21
v[top++] = c;
22
}
23
T pop(){
24
if(top == 0) throw Underflow();
25
return v[--top];
26
}
10
T* v;
11
int max_size;
12
int top;
13 public:
14
class Underflow{ }; // 下溢
15
class Overflow{ };
// 上溢
16
// construct function. determine the size
17
Stack(int s): max_size(s), top(0){ v = new T[max_size];}
5
ቤተ መጻሕፍቲ ባይዱ
cerr << "error: stack overflow" << endl;
6
}
7
catch(Stack<string>::Underflow){
8
cerr << "error: stack underflow" << endl;
9
}
10
分别改成如下:
1
2
class Underflow{
//
3
第三个版本:version3
在 Stack 里面添加一个类 class Stack_error,让 Underflow 和 Overflow 都继承它:
1 template<class T>class Stack{
代码
这里我们就不以前面的除数为 0 的例子来进行异常处理了,因为我不知道如何定义 自己特定错误的 errno,如果哪位知道,希望能给出方法。我以一个网上的例子来 说明它的使用方法:
代码
这里试图打开一个 d 盘的文件,如果文件不存在,这是查看 errno 的值,结果是 2、 当文件存在时,errno 的值为初始值 0。然后查看值为 2 的错误信息,在宏定义那边 #define ENOFILE 2 /* No such file or directory */ 便知道错误的原因了。 4.使用 goto 语句进行异常处理: goto 语句相信大家都很熟悉,是一个跳转语句,我们还是以除数为 0 的例子,来构 造一个异常处理的例子:
#include <stdio.h> #include <setjmp.h> jmp_buf j; void Exception(void) {
longjmp(j,1); }
double diva(double num1,double num2) {
double re; re=num1/num2;
11 scanf("%lf",&a); 12 printf("请输入第二个数字:");
13 scanf("%lf",&b);
14 if(0==b)
//如果除数为 0 终止程序 ,并挂接到模拟异常捕获的注册函
数
15 {
16
17 atexit(Exception);
18 exit(EXIT_FAILURE);
19 }
20 result=diva(a,b);
21 printf("相除的结果是: %.2lf\n",result);
22 return 0;
23 }
这里需要注意的是,atexit()函数总是被执行的,就算没有 exit()函数,当程 序结束时也会被执行。并且,可以挂接多个注册函数,按照堆栈结构进行执行。abort ()函数与 exit()函数类似,当出错时,能使得程序正常退出,这里就不多说了。
27 };
28
29 void f()
30 {
31
Stack<string> ss(10);
32
try{
33
ss.push("Quiz");
34
string s = ss.pop();
35
ss.pop();
36
}
37
catch(Stack<string>::Overflow){
38
cerr << "error: stack overflow" << endl;
public:
4
void error(void){
5
cerr << "stack Underflow" << endl;
6
}
7
};
8
class Overflow{
//
9
public:
10
void error(void){
11
cerr << "stack Overflow" << endl;
12
}
13
49
return EXIT_SUCCESS;
50 }
51
52 输出结果:error: stack underflow
53
54
改进,我们的第二个版本如下:
如果将
1 class Underflow{ }; // 下溢
2
class Overflow{ };
// 上溢
3和
4
catch(Stack<string>::Overflow){
1 version 1
2 // From: An Overview of the C++ Programming Language
3
4 #include <cstdlib>
5 #include <iostream>
6 #include <string>
7 using namespace std;
8
9 template<class T>class Stack{
19 printf("相除的结果是: %.2lf\n",result); 20 return 0; 21 }
其中 exit 的定义如下:
_CRTIMP void __cdecl __MINGW_NOTHROW exit (int) __MINGW_ATTRIB_NORETURN; exit 的函数原型:void exit(int)由此,我们也可以知道 EXIT_FAILURE 宏应该是一个 整数,exit()函数的传递参数是两个宏,一个是刚才看到的 EXIT_FAILURE,还有 一个是 EXIT_SUCCESS 从字面就可以看出一个是出错后强制终止程序,而一个是程 序正常结束。他们的定义是:
C++ 下面的程例来自《An Overview of the C++ Programming Language》(5.1 异常和
错误处理) 程序用途:使用 C++的异常机制,报告 stack 的上溢或者下溢。(我适当的把代码补全。)
version 1 演示了基本的异常用法。
从 try 里抛出一个异常(实例或对象),由 catch 里的类接受。
#define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 到此,当出现异常的时候,程序是终止了,但是我们并没有捕获到异常信息,要捕 获异常信息,我们可以使用注册终止函数 atexit(),它的原型是这样的:
int atexit(atexit_t func); 具体看如下程序:
我们就前面的问题,使用 assert 断言进行异常终止操作:构造可能出现出错的断言 表达式:assert(number!=0)这样,当除数为 0 的时候,表达式就为 false,程序 报告错误,并终止执行。
代码如下:
代码
3.使用 errno 全局变量,进行异常处理: errno 全局变量主要在调式中,当系统 API 函数发生异常的时候,将 errno 变量赋予 一个整数值,根据查看这个值来推测出错的原因。
C 语言异常处理。
三 C 语言中的异常处理
在 C 语言中异常处理一般有这么几种方式:
1.使用标准 C 库提供了 abort()和 exit()两个函数,它们可以强行终止程序的运 行,其声明处于<stdlib.h>头文件中。 2.使用 assert(断言)宏调用,位于头文件<assert.h>中,当程序出错时,就会 引发一个 abort()。 3.使用 errno 全局变量,由 C 运行时库函数提供,位于头文件<errno.h>中。 4.使用 goto 语句,当出错时跳转。 5.使用 setjmp,longjmp 进行异常处理。 接下来,我们就依次对这几种方式来看看到底是怎么做的: 我们仍旧以前面处理除数为 0 的异常为例子。 1.使用 exit()函数进行异常终止:
代码
5.使用 setjmp 和 longjmp 进行异常捕获与处理: setjmp 和 longjmp 是非局部跳转,类似 goto 跳转作用,但是 goto 语句具有局限性, 只能在局部进行跳转,当需要跳转到非一个函数内的地方时就需要用到 setjmp 和 longjmp。setjmp 函数用于保存程序的运行时的堆栈环境,接下来的其它地方,你 可以通过调用 longjmp 函数来恢复先前被保存的程序堆栈环境。异常处理基本方法: 使用 setjmp 设置一个跳转点,然后在程序其他地方调用 longjmp 跳转到该点(抛 出异常). 代码如下所示:
return re; }
int main() {
double a,b,result;
//两数相除函数
printf("请输入第一个数字:"); scanf("%lf",&a); printf("请输入第二个数字:"); if(setjmp(j)==0) { scanf("%lf",&b); if(0==b) Exception(); result=diva(a,b);
printf("相除的结果是: %.2lf\n",result); } else printf("试图除以一个为 0 的数字\n");
return 0; }
四 总结:
除了以上几种方法之外,另外还有使用信号量等等方法进行异常处理。当然在实际 开发中每个人都有各种调式的技巧,而且这文章并不是说明异常处理一定要这样做, 这只是对一般做法的一些总结,也不要乱使用异常处理,如果弄的不好就严重影响 了程序的效率和结构,就像设计模式一样,不能胡乱使用。
2.使用 assert()进行异常处理:
assert()是一个调试程序时经常使用的宏,切记,它不是一个函数,在程序运行时它 计算括号内的表达式,如果表达式为 FALSE (0), 程序将报告错误,并终止执行。 如果表达式不为 0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现 了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错 误。 另外需要注意的是:assert 只有在 Debug 版本中才有效,如果编译为 Release 版本 则被忽略。
1 #include <stdio.h>
2 #include <stdlib.h>
3 double diva(double num1,double num2)
4{
5
double re;
6
re=num1/num2;
7
return re;
8}
9 int main()
10 {
11 double a,b,result;
1 #include <stdio.h>
2 #include <stdlib.h> 3 void Exception(void) 捕获异常信息
//注册终止函数,通过挂接到此函数,
4{
5
printf("试图去除以一个为 0 的数字,出现异常!\n");
6}
7 int main()
8{
9 double a,b,result; 10 printf("请输入第一个数字:");
12 printf("请输入第一个数字:");
13 scanf("%lf",&a);
14 printf("请输入第二个数字:");
15 scanf("%lf",&b);
16 if(0==b)
17 exit(EXIT_FAILURE);
18 result=diva(a,b);
//两数相除函数 //如果除数为 0 终止程序
39
}
40
catch(Stack<string>::Underflow){
41
cerr << "error: stack underflow" << endl;
42
}
43 }
44
45 int main(int argc, char *argv[])
46 {
47
f();
48
system("PAUSE");
};
14 和
15
catch(Stack<string>::Overflow& e){
16
e.error();
17
}
18
catch(Stack<string>::Underflow& e){
19
e.error();
20
}
21
改后的程序和原先的区别在哪里,看出来了吗? 呵呵呵。
当然,我们还能将代码改进。这样产生了第三个版本。
18
~Stack(){}
19
void push(T c){
20
if(top == max_size) throw Overflow();
21
v[top++] = c;
22
}
23
T pop(){
24
if(top == 0) throw Underflow();
25
return v[--top];
26
}
10
T* v;
11
int max_size;
12
int top;
13 public:
14
class Underflow{ }; // 下溢
15
class Overflow{ };
// 上溢
16
// construct function. determine the size
17
Stack(int s): max_size(s), top(0){ v = new T[max_size];}
5
ቤተ መጻሕፍቲ ባይዱ
cerr << "error: stack overflow" << endl;
6
}
7
catch(Stack<string>::Underflow){
8
cerr << "error: stack underflow" << endl;
9
}
10
分别改成如下:
1
2
class Underflow{
//
3
第三个版本:version3
在 Stack 里面添加一个类 class Stack_error,让 Underflow 和 Overflow 都继承它:
1 template<class T>class Stack{