一般说来,当在被某一问题困扰了很长时间,用几天甚至几周查不错代码缺陷的时候,程序员才真正意思到防错性代码的重要性,在编写代码的时候,简单加入几句断言或检查,可能在调试的时候“随手”就能发现并修改这些可能造成严重问题的缺陷。
对于可靠性有苛刻要求的产品,这点尤为重要。
1. 1. 断言
断言用于确保某一个语句或运算结果符合预期,如果不是的话就将程序暂停,便于调试和修改。断言可以消除相互矛盾的假设,消除传入子程序的不良数值等等,在修改代码时可以保护代码改动是否影响到了程序其它部分。
简单的断言包括:指针是否为空,程序不可能运行到的分支(if和swich中),数组下标越界,极小概率会运行到的代码分支等。注意如果断言不是那么“直接明了”,一定要写上注释,为什么会有这样断言。
在头文件UniAssert.h设计了一个简单断言宏UNI_ASSERT,对于类似QT类库,也可以直接使用Q_ASSERT。
1. 2. 错误码
1、设计接口或函数时,必须严谨考虑返回错误码;2、调用接口或函数时,必须检查返回错误码。
忽略错误码,是不可接受的,导致不可预期的问题。甚至在调用认为“不可能出错”的函数时,也应该随手加上断言判断。
在调用接口或函数后,应该紧跟返回错误码的判断,如果出错,输出日志信息。
1. 2. 1. 项目错误码
在UniErrDef.h文件中定义整个项目的错误码,这些错误码比较概括和抽象,在编写代码,应该选择合适含义的错误返回,如果开发人员认为现有错误不能很好反应代码逻辑,可以和负责人提出并增加错误码。
1. 2. 2. 系统错误
调用操作系统函数,至少要判断调用失败,并在失败后输出日志,UNI的日志提供直接输出系统错误输出的功能。
注意,系统调用错误码(比如GetLastError())会在随后的系统调用被覆盖,所以要在某一个系统调用后立刻检查并处理错误码。
1. 2. 3. 第三方库
目前第三方库错误码,是直接封装到UniErrDef.h管理,如STL、gRPC等。
1. 2. 4. C++异常使用
1、本项目不直接设计C++异常类管理错误情况,统一使用错误码。
2、对于第三方库引入的C++异常类,都应该封装到UniErrDef.h中。
3、禁止使用catch(…),在当前代码片段中,只catch能处理的异常,不能处理异常直接抛到上级代码中。
1.3. 输入检查
接口、函数、读取文件后应该对检查所有输入参数的合法性,对参数合法性检查应该成为开发人员的习惯,包括指针的合法性,数组下标,长度,字符串为空等等。 本项目中建议采用“失败即停”原则,1、先检查代码输入参数,不合法则返回;2、不要尝试处理“可能可以运行”的输入数据。