外观
11.程序异常处理的设计
约 1487 字大约 5 分钟
嵌入式数据结构Linux单片机
2022-06-18
二十二、程序异常处理的设计(上)
1.
- 在开发中,不可避免的需要进行异常处理
- 函数调用时的异常
- 并不是指函数设计上的逻辑错误
- 而是可预见的非正常功能的执行分支

2. 异常处理的意义
- 软件开发过程中,大多数情况下都在处理异常情况
- 异常不是错误,但是可能导致程序无法正常执行
- 异常处理直接决定软件产品的鲁棒性和稳定性
3. 项目中的异常设计
- 实现表达异常的通用方法(异常如何表示?)
- 设定异常报告的方法(发生了什么异常?如何知道?)
- 制定统一处理异常的原则(怎么处理异常?)
4. 在C语言中通过错误码对异常进行表示
优势:
- 错误码的定义简单,使用方便
劣势:
- 同一个错误码可能表示不同含义
5. 异常表示的通用设计方法
采用整数分区域的方式对异常进行表示

6. 错误码类型的操作
- ERROR_MARK //0x80000000错误码最高位为1
- ERROR_BEGIN(_module_id) //根据模块ID计算起始错误号
- ERROR_T(_module_error) //根据错误号生成错误码
- MODULE_ERROR(_error_t) //获取错误码中的模块内错误号(低16位)
- MODULE_ID(_error_t) //获取错误码中的模块ID(高15位)
7. 编程实验:错误码的设计与使用
demo1
8. 异常的报告
- 通常情况下,系统日志的是异常报告的主要方式
- 注意:异常报告并不是异常处理
- 异常报告用于记录异常的发生
- 异常处理用于阻止异常导致的程序崩溃
9. 异常报告与异常处理示例(整体框架)

10. 异常报告与异常处理示例(异常报告)

11. 异常报告与异常处理示例(异常处理)

12. 工程开发时的一些建议
尽量在异常发生的地方报告异常
- 有助于事后找到异常发生时的函数调用路径
尽量在上层函数中统一处理异常
- 集中处理异常有助于提高代码的维护性
13. 实例分析:异常报告与处理
demo2
14. 小结
- C 项目中通常采用整数分区域的方式对异常进行表示
- 异常号包含了模块信息以及模块相关的具体异常信息
- 通常情况下,系统日志的是异常报告的主要方式
- 尽量就近报告异常,尽量统一处理异常
To be continued …
当前的设计中,直接输出异常号的方式易于问题定位吗?是否更好的异常输出方式?
二十三、程序异常处理的设计(中)
1. 期望的异常输出方式
- 直接将错误码所对应的枚举常量名输出
- 枚举常量名是精心设计的有意义的名字
- 枚举常量名包含了模块名和模块内错误名
2. 期望的异常输出方式

3. 思路
- 建立枚举常量名到字符串数组的映射
- 通过错误号查找字符串数组得到对应的名字

4. 维护性上的考虑
- 每个模块有自己的异常枚举定义(数量不同)
- 异常的类型无法一次性设计完善(后期可能增加或减少)
- 当异常类型改动时,必须正确改动对应的字符串数组
5. 解决方案设计
1. 每个模块的异常枚举定义于独立的文件
2. 异常枚举的定义遵循固有的编码规范
3. 编写独立程序处理异常枚举定义文件,生成对应的字符串数组
4. 当项目中出现异常时
- 根据错误码中的模块名定位字符串数组
- 根据错误码中的内部错误号定位字符串
6. 解决方案设计
7. 编程实验:自动代码生成
8. 错误码到枚举常量名的映射

9. 数据结构设计

10. 错误名查找函数的设计

11. 文件之间的依赖关系

12. 编程实验:编译自动生成的代码
13. 小结
- 异常输出时,期望的是可读性强的描述,而不是错误码
- 使用独立程序自动建立错误码到字符信息的映射
- 代码自动生成技术建立于项目中的代码规范之上
- 当项目中有固定规则编写的代码时,可以考虑代码自动生成
二十四、程序异常处理的设计(下)
1. 自动代码生成需要考虑的问题
输入
- 如果是数据(非代码)→ 数据是否被格式化组织(XML, JSon)
- 如果是代码 → 代码是否遵循严格的编码规范(有规律可循)
输出
- 是否需要基于代码模板完成?
- 是否需要动态 “组装” 生成代码?
2. 问题分析

3. 处理流程设计

4. 实例分析:代码分析
err2str.cpp
5. 小结


