C语言异常处理

article/2025/9/14 0:14:20

文章目录

  • 前言
  • 一、 异常表达
  • 二、 异常报告
  • 三、 异常处理

前言

错误与异常:
错误与异常都是在程序编译或者运行时出现的错误, 不同的是,异常可以被开发人员捕捉和处理;而错误,一般不需要开发人员处理(也无法处理),比如内存溢出,如果异常未及时被处理,也可能产生错误。


在开发中,不可避免的需要对异常进行处理,如函数调用时候的异常:

  • 不是指函数设计上的错误
  • 而是可以预见的非正常功能的分支

例:

char* strcpy(char* des,const char* source)
{char* r=des;assert((des != NULL) && (source != NULL));while((*r++ = *source++) != '\0');return des;
}

异常处理的意义:

  • 软件开发过程中,大多数时候都在处理异常情况
  • 异常不是错误,但是可能导致程序无法正常运行
  • 异常处理直接决定软件的鲁棒性和稳定性

一、 异常表达

在C语言中通常通过错误码表示异常,例如Linux中的错误码
优势:错误码定义简单,使用方便
劣势:同一个错误码,在不同程序中意义不仅相同

ErrnoErrno号码说明
EINTR4系统调用中断。
EAGAIN11资源临时不可用。
EBUSY16资源正忙。
EMFILE24每个进程文件描述符表已满。
EPIPE32管道断开。

异常表示的通用设计方法:采用整数分区域的方式对异常进行表示

bit31bit30 - bit16bit15-bit0
1模块标识错误标识

最高位为符号位,固定为1则所有的错误码都是负数。

err_def.h定义了异常标识和模块标识

#ifndef ERR_DEF_H
#define ERR_DEF_H#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>typedef int32_t err_t;// 模块数量
#define MODULE_COUNT 2
// 将最高位设为1构成错误码
#define ERR_CONSTRUCT(_error_) ((_error_) | (1 << 31))
// 根据模块标识确认第一个错误标识的值
#define ERR_CODE_BEGIN(_module_) ((_module_) << 16)
// 获取模块ID
#define ERR_GET_MODULE_ID(_error_) (((_error_) >> 16) & 0x7fff)
// 获取错误标识在数组中的下标
#define ERR_GET_ERROR_INDEX(_error_) ((_error_) & 0xffff)
// 获取错误标识
#define ERR_GET_ERROR_CODE(_error_) ((_error_) & 0x7fffffff)typedef enum {TIMER_MODULE,LCD_MODULE
} module_enum_t;typedef enum {TIMER_ERR_OK = ERR_CODE_BEGIN(TIMER_MODULE),TIMER_ERR_MEM,TIMER_ERR_BUF,TIMER_ERR_TIMEOUT,TIMER_ERR_VAL
} timer_err_enum_t;typedef enum {LCD_ERR_OK = ERR_CODE_BEGIN(LCD_MODULE),LCD_ERR_MEM,LCD_ERR_BUF,LCD_ERR_TIMEOUT,LCD_ERR_VAL
} lcd_err_enum_t;#endif

二、 异常报告

通常情况下,系统日志是报告异常的主要形式,但是异常报告并不是处理异常,异常报告只负责记录,而异常处理用于阻止异常程序的崩溃。


异常报告实例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "err.h"// 将异常进行输出
#define LOG(errno) printf("[%s:%d] Errno: %x\n", __FILE__, __LINE__, errno)err_t lcd_init()
{err_t ret = ERR_CONSTRUCT(LCD_ERR_TIMEOUT);return ret;
}
int main()
{err_t ret = lcd_init();if(LCD_ERR_OK != ret){LOG(ret);}
}

结果如下,直接打印出错误码,但是可能我们还得自己去查找具体的错误信息。
在这里插入图片描述

直接将异常标识和异常打印出来并不友好,不便于定义问题,因此我们希望有更加直观的异常输出方式:

  • 直接将错误码对应的常量名字进行输出
  • 枚举常量名包含了模块名和模块内部错误标识
    类似下面这样的形式
#ifndef MODULE_H
#define MODULE_Htypedef enum {LCD_ERR_OK = ERR_CODE_BEGIN(LCD_MODULE),LCD_ERR_MEM,LCD_ERR_BUF,LCD_ERR_TIMEOUT,LCD_ERR_VAL
} lcd_err_enum_t;static const char *lcd_error_str[] = {"LCD_ERR_OK","LCD_ERR_MEM","LCD_ERR_BUF","LCD_ERR_TIMEOUT","LCD_ERR_VAL"
}
#endif

但是错误标识在开发过程中可能经常发生变动,那么对应的字符数组也要同样变化,在修改过程中非常容易产生错误,需要特别注意,后续将介绍使用自动化代码生成工具,这样只需要定义对应的错误码就可以了,字符串数组自动生成。
工具链接

接下来要做的就是把所有模块的错误标识字符数组关联起来,通过
const char* errno_to_str(err_t errno)转换成为对应的输出:

#include "err.h"static struct error_str_t
{// 错误码标识字符数组是否存在bool exist;// 最后一个错误标识值int last_error;// 数组指针const char ** error_array;
}s_error_str_array[MODULE_COUNT];// 对应的错误标识字符数组
static const char *s_timer_error_str[] = {"TIMER_ERR_OK","TIMER_ERR_MEM","TIMER_ERR_BUF","TIMER_ERR_TIMEOUT","TIMER_ERR_VAL"};
static const char *s_lcd_error_str[] = {"LCD_ERR_OK","LCD_ERR_MEM","LCD_ERR_BUF","LCD_ERR_TIMEOUT","LCD_ERR_VAL"};// 初始化 s_error_str_array 数组
void error_str_init()
{s_error_str_array[TIMER_MODULE].exist = true;s_error_str_array[TIMER_MODULE].last_error = 4;s_error_str_array[TIMER_MODULE].error_array = s_timer_error_str;s_error_str_array[LCD_MODULE].exist = true;s_error_str_array[LCD_MODULE].last_error = 4;s_error_str_array[LCD_MODULE].error_array = s_lcd_error_str;
}// 把错误码转换成字符串
const char* error_to_str(err_t errno)
{static bool initialized = false;// 根据错误码获取16位错误标识uint16_t error_code = ERR_GET_ERROR_INDEX(errno);// 根据错误码获取15位模块标识uint16_t module_id = ERR_GET_MODULE_ID(errno);if(!initialized){error_str_init();initialized = true;}if(errno > 0)return "Errno should less than 0";if(!s_error_str_array[module_id].exist)return "Error code array isn't exist";if(s_error_str_array[module_id].last_error < error_code)return "Error code out of range";return s_error_str_array[module_id].error_array[error_code];
}

代码中通过模块ID和错误标识找到对应的字符串前需要对s_error_str_array进行初始化(字符数组的生成,初始化,都可以通过自动化完成,但是需要遵循一定的规范)

在这里插入图片描述

最后将LOG进行修改,让他可以输出更多信息

// 将异常进行输出
#define LOG(errno) do{ \const char* str = error_to_str(errno); \printf("[%s:%d] Errno: %s\n", __FILE__, __LINE__, str); \
}while(0)

最终的结果,通过对应名字就可以知道错误类型
在这里插入图片描述

三、 异常处理

异常处理示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "err.h"// 将异常进行输出
#define LOG(errno) do{ \const char* str = error_to_str(errno); \printf("[%s:%d] Errno: %s\n", __FILE__, __LINE__, str); \
}while(0)err_t lcd_init()
{err_t ret = ERR_CONSTRUCT(LCD_ERR_TIMEOUT);return ret;
}
// 集中进行异常处理
bool lcd_error_handle(err_t errno)
{bool ret = true;err_t err = ERR_GET_ERROR_CODE(errno);switch(err){case LCD_ERR_MEM:break;default:break;}// 如果函数无法处理直接exit结束if(!ret){exit(0);}return ret;
}int main()
{err_t ret = lcd_init();if(LCD_ERR_OK != ret){LOG(ret);lcd_error_handle(ret);}
}

尽量在发生异常的地方报告异常,有助于找到异常发生时候的调用路径。
尽量在上层函数中统一异常,集中处理异常有助于提高代码的可维护性。


http://chatgpt.dhexx.cn/article/4kyW7ZI6.shtml

相关文章

SpringBoot全局异常处理

文章目录 异常处理方案分类基于请求转发基于异常处理器基于过滤器 常见异常处理实现方案1. BasicExceptionController2. ExceptionHandler3. ControllerAdviceExceptionHandler4. SimpleMappingExceptionResolver5. HandlerExceptionResolver6. Filter 全局异常处理实现方案1. …

springboot整合之统一异常处理

特别说明&#xff1a;本次项目整合基于idea进行的&#xff0c;如果使用Eclipse可能操作会略有不同&#xff0c;不过总的来说不影响。 springboot整合之如何选择版本及项目搭建 springboot整合之版本号统一管理 springboot整合mybatis-plusdurid数据库连接池 springboot整合…

C++ 异常处理

目录 一、异常的定义 二、异常的抛出和捕获 1.throw 2.try...catch 3.异常安全 4.异常规范 三、系统预定义异常 四、用户自定义异常 一、异常的定义 异常在C用于错误处理&#xff0c;C语言中一般使用返回值表示错误&#xff0c;C对错误处理进行了扩展&#xff0c;统一使…

关于异常处理的知识整理

目录 1.什么是异常&#xff1f; 2.异常继承结构 3.异常结构继承图 4.关于异常处理的两种方式&#xff1a; 5.异常对象有两个非常重要的方法 1.什么是异常&#xff1f; 程序在执行过程中不正常的情况称为异常&#xff0c;以类和对象的形势存在&#xff0c;可以通过异常类&am…

异常处理---

异常 异常处理 例&#xff1a; public class Demo{public static void main(String[] args) {System.out.println("开始");method();System.out.println("结束");}public static void method(){int[] arr{1,2,3};System.out.println(arr[3]);//数组索引…

异常处理

1.相关概念的介绍 1&#xff09;异常情形&#xff1a;是指阻止当前方法或作用域继续执行的问题。 2&#xff09;监控区域&#xff1a;一段可能产生异常的代码&#xff0c;并且后面跟着处理这些异常的代码。 3&#xff09;try块&#xff1a;如果在方法的内部或者在方法内部调…

异常及异常处理

一、异常的概念 定义&#xff1a; 异常指的是运行期出现的错误&#xff0c;也就是当程序开始执行以后执行期出现的错误。 处理态度&#xff1a; 当捕获到异常以后一定要做出处理&#xff0c;哪怕是把这个异常的错误信息打印出来&#xff0c;这是一种良好的编程习惯。 …

异常处理(throw、throws、try-catch)

Java异常处理的五个关键字try、catch、finally、throw、throws 1.抛出异常throw 在编写程序时&#xff0c;我们必须要考虑程序出现问题的情况。比如&#xff0c;在定义方法时&#xff0c;方法需要接收参数。那么&#xff0c;当调用方法使用接收到的参数时&#xff0c;首先需要…

SpringBoot+Axis2搭建WebService服务端

SpringBootAxis2搭建WebService服务端 之前用过Spring Axis2搭建过WebService项目&#xff0c;网上也有很多资料教程&#xff0c;最近需要在一个SpringBoot项目中添加Axis2的服务端&#xff0c;在网上找了很久&#xff0c;没有找到相关教程&#xff0c;最终经过大神朋友的指点…

AXI(2)完结

四、握手 4.1握手过程 所有的五个通道都是通过相同的VALID/READY握手处理来传输地址、数据和控制信息。 双向握手的机制意味着主机和从机之间传输数据时&#xff0c;都可以控制传输的速率&#xff0c;只有当VALID和READY同时为高电平时&#xff0c;传输才会发生。 发送方&a…

读Axis2用户帮助文档 (axis2中文文档)

作者&#xff1a;李红霞 时间&#xff1a;2006-10-19 声明&#xff1a;本文可以算作Axis2用户手册的翻译&#xff0c;但是翻译后的文本是经过作者理解写出来的&#xff0c;可能有些偏差&#xff0c;欢迎讨论。本文属作者原创&#xff0c;允许转载&#xff0c;但请注明出处。 英…

AXI 3.0 (1)

一、AXI简介 AMBA3.0中新增加了一种总线——AXI&#xff08;Advanced eXtensible Interface&#xff0c;高级扩展接口&#xff09;。 AMBA AXI 协议的目标是高性能、高频的系统设计&#xff0c;其包含了若干特性。 适合高带宽和低延迟的设计 提供高频操作&#xff0c;无需使…

Apache axis2 + Eclipse 开发 WebService

一、简介 Apache Axis2是下一代 Apache Axis。Axis2 虽然由 Axis 1.x 处理程序模型提供支持&#xff0c;但它具有更强的灵活性并可扩展到新的体系结构。Axis2 基于新的体系结构进行了全新编写&#xff0c;而且没有采用 Axis 1.x 的常用代码。支持开发 Axis2 的动力是探寻模块化…

Axis2与Web项目整合

一、说明: 上一篇介绍了通过使用Axis2来发布和调用WebService&#xff0c;但是是把WebService发布在Axis2提供的项目中&#xff0c;如果我们需要在自己的Web项目中来使用Axis2发布WebService该怎么做呢&#xff1f; 本篇即介绍在Web项目中使用Axis2来发布WebService. 二、具体…

Axis2中文手册

中文原文 http://tenn.javaeye.com/blog/100736 英文原文 http://ws.apache.org/axis2/1_0/userguide.html 概述 这个说明文档涉及以下内容&#xff1a;  如何使用 axis2 创建 web service 和客户端程序  如何定制一个模块 (Module) 并在 web service 中使用它  Sam…

axis2的使用(转载)

通过axis2发起WS请求时添加SOAP header 首先要获得一个ServiceClient对象&#xff0c;因为这个对象是org.apache.axis2.client.Stub里面定义的&#xff0c;所以你生成的stub里面应该直接就可以使用这个对象&#xff0c;或者调用stub的_getServiceClient()方法来获取这个对象。 …

SpringBoot2 整合 AXIS2 服务端和客户端

文章目录 一、AXIS2服务端1. 版本选型2.导入依赖3. services.xml4.Axis2配置类5.服务接口6.服务接口实现类7. FileCopyUtils工具类8. 测试验证 二、AXIS2服务端2.1. 客户端类2.2. 服务调用测试开源源码. 一、AXIS2服务端 1. 版本选型 阿健/框架版本spring-boot2.5.5axis21.7.…

WebService之Axis2系列教程(一)Axis2的下载、安装和使用

Axis2是目前比较流行的WebService引擎。WebService被应用在很多不同的场景。例如&#xff0c;可以使用WebService来发布服务端 Java类的方法&#xff0c;以便使用不同的客户端进行调用。这样可以有效地集成多种不同的技术来完成应用系统。WebService还经常被使用在SOA中&#x…

Axis2 webservice学习总结

一、学习课件目录&#xff1a; Axis2(WebService)培训资料1 - 百度文库 (baidu.com) WebService大讲堂之Axis2 - 百度文库 (baidu.com) 二、学习总结&#xff1a; Web Service是构建互联网分布式系统的基本部件&#xff0c;它是一个应用程序&#xff0c;它向外界暴露出一个…

小白轻松使用axis2构建webservice

引言&#xff1a; 使用axis2是来实现webservice接口是比较常见的&#xff0c;就我来说&#xff0c;如果要学一个首次接触东西&#xff0c;简单了解相关基础概念后&#xff0c;就希望自己能够简单快速的实现一个例子&#xff0c;在学习一门开发语言的时候&#xff0c;一个hello…