C 错误处理
Posted 三季人 G
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C 错误处理相关的知识,希望对你有一定的参考价值。
C 错误处理
C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。您可以在 errno.h 头文件中找到各种各样的错误代码。
所以,C 程序员可以通过检查返回值,然后根据返回值决定采取哪种适当的动作。开发人员应该在程序初始化时,把 errno 设置为 0,这是一种良好的编程习惯。0 值表示程序中没有错误。
errno、perror() 和 strerror()
C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。
- perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
- strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
让我们来模拟一种错误情况,尝试打开一个不存在的文件。您可以使用多种方式来输出错误消息,在这里我们使用函数来演示用法。另外有一点需要注意,您应该使用 stderr 文件流来输出所有的错误。
举例:
#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno ;
int main ()
FILE * pf;
int errnum;
pf = fopen ("unexist.txt", "rb");
if (pf == NULL)
errnum = errno;
fprintf(stderr, "错误号: %d\\n", errno);
perror("通过 perror 输出错误");
fprintf(stderr, "打开文件错误: %s\\n", strerror( errnum ));
else
fclose (pf);
return 0;
当上面的代码被编译和执行时,它会产生下列结果:
错误号: 2
通过 perror 输出错误: No such file or directory
打开文件错误: No such file or directory
捕获异常
我们可以借助 C++ 异常机制来捕获上面的异常,避免程序崩溃。捕获异常的语法为:
try
// 可能抛出异常的语句
catch(exceptionType variable)
// 处理异常的语句
try和catch都是 C++ 中的关键字,后跟语句块,不能省略
。try 中包含可能会抛出异常的语句,一旦有异常抛出就会被后面的 catch 捕获。从 try 的意思可以看出,它只是“检测”语句块有没有异常,如果没有发生异常,它就“检测”不到。catch 是“抓住”的意思,用来捕获并处理 try 检测到的异常;如果 try 语句块没有检测到异常(没有异常抛出),那么就不会执行 catch 中的语句。
这就好比,catch 告诉 try:你去检测一下程序有没有错误,有错误的话就告诉我,我来处理,没有的话就不要理我!
**catch 关键字后面的exceptionType variable
**
指明了当前 catch 可以处理的异常类型,以及具体的出错信息。我们稍后再对异常类型展开讲解,当务之急是演示一下 try-catch 的用法,先让读者有一个整体上的认识。
【例2】加入捕获异常的语句:
#include <iostream>
#include <string>
#include <exception>
using namespace std;
int main()
string str = "http://c.biancheng.net";
try
char ch1 = str[100];
cout<<ch1<<endl;
catch(exception e)
cout<<"[1]out of bound!"<<endl;
try
char ch2 = str.at(100);
cout<<ch2<<endl;
catch(exception &e) //exception类位于<exception>头文件中
cout<<"[2]out of bound!"<<endl;
return 0;
运行结果:
[2]out of bound!
可以看出,第一个 try 没有捕获到异常,输出了一个没有意义的字符(垃圾值)。因为[ ]
不会检查下标越界,不会抛出异常,所以即使有错误,try 也检测不到。换句话说,发生异常时必须将异常明确地抛出,try 才能检测到;如果不抛出来,即使有异常 try 也检测不到。所谓抛出异常,就是明确地告诉程序发生了什么错误。
第二个 try 检测到了异常,并交给 catch 处理,执行 catch 中的语句。需要说明的是,异常一旦抛出,会立刻被 try 检测到,并且不会再执行异常点(异常发生位置)后面的语句。本例中抛出异常的位置是第 17 行的 at() 函数,它后面的 cout 语句就不会再被执行,所以看不到它的输出。
说得直接一点,检测到异常后程序的执行流会发生跳转,从异常点跳转到 catch 所在的位置,位于异常点之后的、并且在当前 try 块内的语句就都不会再执行了;即使 catch 语句成功地处理了错误,程序的执行流也不会再回退到异常点,所以这些语句永远都没有执行的机会了。本例中,第 18 行代码就是被跳过的代码。
执行完 catch 块所包含的代码后,程序会继续执行 catch 块后面的代码,就恢复了正常的执行流。
为了演示「不明确地抛出异常就检测不到异常」,大家不妨将第 10 行代码改为char ch1 = str[100000000];
,访问第 100 个字符可能不会发生异常,但是访问第 1 亿个字符肯定会发生异常了,这个异常就是内存访问错误。运行更改后的程序,会发现第 10 行代码产生了异常,导致程序崩溃了,这说明 try-catch 并没有捕获到这个异常。
关于「如何抛出异常」,我们将在下节讲解,这里重点是让大家明白异常的处理流程:
抛出(Throw)--> 检测(Try) --> 捕获(Catch)
发生异常的位置
异常可以发生在当前的 try 块中,也可以发生在 try 块所调用的某个函数中,或者是所调用的函数又调用了另外的一个函数,这个另外的函数中发生了异常。这些异常,都可以被 try 检测到。
- 下面的例子演示了 try 块中直接发生的异常:
#include <iostream>
#include <string>
#include <exception>
using namespace std;
int main()
try
throw "Unknown Exception"; //抛出异常
cout<<"This statement will not be executed."<<endl;
catch(const char* &e)
cout<<e<<endl;
return 0;
运行结果:
Unknown Exception
throw
关键字用来抛出一个异常,这个异常会被 try 检测到,进而被 catch 捕获。关于 throw 的用法,我们将在下节深入讲解,这里大家只需要知道,在 try 块中直接抛出的异常会被 try 检测到。
- 下面的例子演示了 try 块中调用的某个函数中发生了异常:
#include <iostream>
#include <string>
#include <exception>
using namespace std;
void func()
throw "Unknown Exception"; //抛出异常
cout<<"[1]This statement will not be executed."<<endl;
int main()
try
func();
cout<<"[2]This statement will not be executed."<<endl;
catch(const char* &e)
cout<<e<<endl;
return 0;
运行结果:
Unknown Exception
25.错误处理
//C错误处理 /* C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许访问底层数据 在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL, 同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。 可以在 errno.h 头文件中找到各种各样的错误代码。 所以,C 程序员可以通过检查返回值,然后根据返回值决定采取哪种适当的动作。 开发人员应该在程序初始化时,把 errno 设置为 0,这是一种良好的编程习惯。0 值表示程序中没有错误。 */ //errno、perror() 和 strerror() /* C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。 perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。 strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。 让我们来模拟一种错误情况,尝试打开一个不存在的文件。 以使用多种方式来输出错误消息,在这里我们使用函数来演示用法。 另外有一点需要注意,应该使用 stderr 文件流来输出所有的错误。 */ #include <stdio.h> #include <errno.h> #include <string.h> extern int errno ; int main01 () { FILE * pf; int errnum; pf = fopen ("unexist.txt", "rb"); if (pf == NULL) { errnum = errno; fprintf(stderr, "错误号: %d ", errno); perror("通过 perror 输出错误"); fprintf(stderr, "打开文件错误: %s ", strerror( errnum )); } else { fclose (pf); } return 0; /* 错误号: 2 通过 perror 输出错误: No such file or directory 打开文件错误: No such file or directory */ } //被零除的错误 /* 在进行除法运算时,如果不检查除数是否为零,则会导致一个运行时错误。 为了避免这种情况发生,下面的代码在进行除法运算前会先检查除数是否为零: */ #include <stdio.h> #include <stdlib.h> int main02() { int dividend = 20; int divisor = 0; int quotient; if( divisor == 0){ fprintf(stderr, "除数为 0 退出运行... "); exit(-1); } quotient = dividend / divisor; fprintf(stderr, "quotient 变量的值为 : %d ", quotient ); exit(0); //数为 0 退出运行... } //程序退出状态 /* 通常情况下,程序成功执行完一个操作正常退出的时候会带有值 EXIT_SUCCESS。 在这里,EXIT_SUCCESS 是宏,它被定义为 0。 如果程序中存在一种错误情况,当您退出程序时,会带有状态值 EXIT_FAILURE,被定义为 -1。 */ int main() { int dividend = 20; int divisor = 5; int quotient; if( divisor == 0){ fprintf(stderr, "除数为 0 退出运行... "); exit(EXIT_FAILURE); } quotient = dividend / divisor; fprintf(stderr, "quotient 变量的值为: %d ", quotient ); exit(EXIT_SUCCESS); //quotient 变量的值为: 4 }
以上是关于C 错误处理的主要内容,如果未能解决你的问题,请参考以下文章