C 错误处理

news/2025/1/18 3:25:20/

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 检测到。

  1. 下面的例子演示了 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 检测到。

  1. 下面的例子演示了 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

http://www.ppmy.cn/news/38583.html

相关文章

【动手学习深度学习笔记】

第二章预备知识 节省内存&#xff1a;使⽤切⽚表⽰法将操作的结果分配给先前分配的数组 Z[:] XY就可以把结果覆盖在Z的原内存上&#xff0c;而不是新开辟内存&#xff0c;就节省了内存了 处理缺失值 inputs,outputs data.iloc[:,0:2],data.iloc[:,2] # iloc为位置索引 in…

ABC252 D - Distinct Trio

还有一天就篮球被了&#xff0c;好紧脏.... 我的世界将被摧毁&#xff0c;也许事与愿违 是时候放弃一些东西了呢 D - Distinct Trio (atcoder.jp) 思路&#xff1a; 注意到值域很小&#xff0c;我们可以用值域的前缀和来维护全局哈希&#xff0c;即用前缀和来维护多少数比x…

华为OD机试-最多组合直角三角形个数-2022Q4 A卷-Py/Java/JS

题目描述 有N条线段&#xff0c;长度分别为a[1]-a[n]。 现要求你计算这N条线段最多可以组合成几个直角三角形。 每条线段只能使用一次&#xff0c;每个三角形包含三条线段。 输入描述 第一行输入一个正整数T(1<T<100)&#xff0c;表示有T组测试数据. 对于每组测试数据&…

自然语言处理(七): Deep Learning for NLP: Recurrent Networks

目录 1. N-gram Language Models 2. Recurrent Neural Networks 2.1 RNN Unrolled 2.2 RNN Training 2.3 (Simple) RNN for Language Model 2.4 RNN Language Model: Training 2.5 RNN Language Model: Generation 3. Long Short-term Memory Networks 3.1 Language M…

机器学习:无监督学习之deep generative model

无监督学习 费曼的思想&#xff1a;what i can not create, i do not understand 不知道怎么产生的话&#xff0c;是不能完全理解的。 Create - Image Processing Generative Models PixelRNN 输入一个3x3的像素块&#xff0c;输出3x3的像素块。再把所有的加入继续送入网络输…

【C++从0到1】12、C++11初始化赋值

C从0到1全系列教程 1、C和C11初始化赋值 把值写在小括号中&#xff0c;等于号可以省略&#xff08;C标准&#xff09; int a(15); // 声明变量a&#xff0c;初始化值为15。 int b(20); // 声明变量b&#xff0c;初始化值为20。把值写在花括号中&#xff0c;等于号也可以省略…

fcpx快闪插件推荐,让视频片头片尾更动感

FCPX快闪插件是一款为苹果Final Cut Pro X软件开发的过渡特效插件&#xff0c;可以帮助用户在视频剪辑中添加各种炫酷的快闪转场效果。以下是不错的fcpx快闪插件推荐&#xff1a; FCPX插件-快闪欢快节奏图文展示开场片头Clean Fast Opener 是快闪动感节奏图文展示片头视频FCP…

蓝桥杯最终测试

本次测试包含基本底层——在不冲突的条件下&#xff0c;其包含了数码管&#xff0c; led&#xff0c;按键&#xff0c; DS13B20,DS1302,EEMPRO,串口的使用&#xff0c;等明天会更新其他的NE555(5位)以及超声波的使用 hc573.c #include <STC15F2K60S2.H>void SelectHC573…