转载请注明出处:http://blog.youkuaiyun.com/wangxiaolong_china
检查范围 | 检查项 | 检查原因 | 典型事例 |
命名规范 | 有意义的变量或常量命名符合习惯吗? | 提高可读性 | 比如程序中约定的所有端口定义为port,所有通道定义为path |
多个数据命名时容易引起混淆吗? | 提高可读性 | 程序中一会使用clk表示时钟,一会又使用timer来表示时钟 | |
变量的类型定义合适吗? | 避免数据范围导致的bug | 有符号和无符号,INT还是long,需要保证数据的类型定义满足逻辑表示的需要 | |
变量名重复么 | 避免变量的错误使用导致bug | 不要在一个函数实现中定义两个同名但作用域不同的变量 | |
数组使用 | 不要使用立即数定义数组大小 | 避免数组范围和访问bug | int intarray[13]; |
数组大小定义是否足够 | 避免数组越界范围的bug | char entry[TOTAL_ENTRIES]; | |
数组访问越界了吗 | 避免数组越界范围的bug | 任何情况下都应该保证数组下标不会超过数组的最大范围,这个是及其容易导致的错误. 使用复杂变化的变量或其他外部传入的变量来做数组下标而不加检查的话,程序很难保证数组下标的合理性 | |
常量 | 应该定义成常量的定义成了变量 | 提高效率,编码数据被修改 | int months_in_year = 12; |
可以定义成常量的地方不要使用#define定义 | 提高代码纠错能力 | 缺陷: #define MAX_FILES 20 | |
只在某个类中实现时用到的常量定义是否定义成了全局的 | 提高代码内聚和封装性 | 缺陷: | |
变量使用 | 程序使用float 或 double恰当吗 | 提高代码效率 | 缺陷: double acct_balance; |
变量是否初始化了 |
| 在任何情况下,变量都需要初始化 | |
变量范围是否足够表示数据 | 避免数据范围导致的bug |
| |
类使用 | 有虚函数的类的析构函数定义成了虚函数了吗 | 避免内存泄漏 | 存在虚函数的意义在于允许类继承,而类继承时,为了让隐私类销毁时正确调用到该派生类析构函数,必须将基类析构定义成虚函数. |
拷贝构造,运算符重载,析构实现完整了吗 | 提高类完整性 | 通常情况下,拷贝构造,运算符重载和析构应该三者同时实现,唯一例外是只有析构没有其它两个实现. | |
是否正确避免了没实现赋值重载操作符的类被错误的调用了系统缺省赋值操作 | 保证类定义完整性 | 在没有实现某个操作符重载函数时,类是否避免了外部调用系统提供的缺省的赋值操作 | |
类的成员变量是否已经尽可能的封装到类内部了 | 提高封装性 | 不要将可以private的类成员声明成了public,这样会导致类封装变差 | |
每一个派生类中都需要的成员变量应该定义在基类中 | 提高复用性 | 这样可以最大发挥类继承的效果.便于在基类中提供统一的处理和相关实现 | |
类继承层次单一 | 降低复杂性,提高可读性 | 不要设计非单一层次的类继承.复杂的继承关系会导致实现难于控制,除非是纯虚接口 | |
构造函数中分配系统资源了么(内存,互斥量等) | 降低出错概率 | 不推荐在类构造函数中申请内存.原因是目前系统不处理异常,而构造时申请内存如果不成功,会直接因为系统无法处理操作系统抛出的异常而导致程序崩溃 | |
字符串使用 | 字符串是以null结尾的吗? | 避免字符串越界bug | 任何情况下,都应该保证字符串以null作为正确结尾,否则会产生一项不到的后果 |
是否使用std::string | 防止字符串操作出错 | 在资源允许的情况下,尽量使用std::string,除非是效率要求高,特殊算法,在内核驱动等情况下 | |
宏定义 | 如果宏参数在宏定义中出现多次,要避免宏展开时导致的逻辑错误? | 避免宏使用出错 | 缺陷: |
宏定义的运算结果加了括号吗 | 避免宏使用出错 | 任何情况下,如果宏中存在运算,将运算结果定义加上括号,可以避免在宏展开时导致一些异常情况发生 | |
宏定义中,参数加了括号了吗? | 避免宏使用出错 | #define IsXBitSet(var) (var && bitmask) | |
内存分配和释放 | 代码分配内存但是假定了在别处释放吗 | 避免内存使用错误 | 在一处分配内存,希望再其它地方释放,这种做法一般不会有问题,但是容易导致错误.至少应该做到如下几点:详细设计文档或相关代码中一定要明确写明;除非将其封装为一个类,在构造时申请并在析构时释放掉内存.如果内存申请后可能多次使用,但不能确切知道最后一次使用,可以考虑使用引用计数的方式 |
程序应当尽量使用new而不是使用相关C函数来分配内存? |
| malloc(), calloc(), or realloc()都是C函数,一般情况下C++程序应该尽量使用new而不是这些C函数来分配内存 | |
数组释放正确吗 |
| 缺陷: delete myCharArray; | |
在多处使用的内存指针尽量使用share_ptr模板 |
|
| |
释放后指针是否设为空 |
| 避免重复释放 | |
释放内存前是否判断指针为空 |
| 避免重复释放 | |
运算 | 尽量不要使用运算符的缺省优先级而使用括号来消除疑惑? | 避免优先级出错 | 缺陷: if ( a = function() == 0 ) |
你想要=还是==? | 防止错误输入 | 缺陷: if ( a = function()) | |
是否有些需要同步的数据并没有被更新? | 保证正确性 | 有时,多个数据形成一组数据,这一组数据中具有紧密的相关性,程序应该保证在刷新其中一个数据时保证其它相关数据的同步刷新.否则任何中间状态的组合取值都可能因为无意义而导致程序逻辑运算异常 | |
数据在运算是是否发生了上溢或下溢错误? |
| 当运算发生了溢出错误时,往往时定义的数据类型过小导致,多数情况下不会发生溢出,但需要仔细计算和对运算数据取值范围做精确评估 | |
不要试图精确判断浮点数大小 |
| if ( someVar == 0.1 ) someVar为浮点数时可能永远都得不到正确的值.解决方法是使用>,>=,<=这类判断来确定浮点数的值. | |
不要试图去判断一个无符号数>=0 |
| 缺陷: if ( myUnsignedVar >= 0 ) | |
使用有符号数做计数器时,对边界值判断最好不要使用== |
| 缺陷: if ( mySignedVar ) | |
在两个不同类型的变量之间做比较吗? |
| 尽量不在两个不同类型的变量之间做比较. | |
不要混用了|和||? |
| 这两个运算符功能完全不同,只是看起来有些象而已 | |
不要混用了&和&& |
| 这两个运算符功能完全不同,只是看起来有些象而已 | |
switch | 每个switch的case分支都有break结尾吗? |
| 一般情况下,每个switch的case分支都应该有break结尾,如果没有,很可能执行结果并不是期望的执行逻辑.如果的确期望这样的结果,建议合并这几个case而不是写出这种缺少break的case分支.如果的确需要这样做,详细的代码注释加以解释是非常必要的 |
Switch的某个case以return结束时注意释放相关资源了吗? |
| 一般情况下,case的结束应该使用break,这样在switch处理结束后可能需要对相关资源的释放操作才会得到正确的执行.如果以return结束case分支,需要关注是否正确的释放了相关资源(互斥量,内存等). | |
Switch缺少default处理吗 |
| 即使你100%肯定不需要default,也请提供一个default函数,这样做至少给程序的可扩展性带来好处 | |
循环 | 循环判断条件是否超过了循环变量的表示范围 |
| 例如for (Octet loop=0; loop < 500; loop++),显然是一个死循环 |
正确选择了3种循环体了吗? |
| for /do while/while三种循环体适用的地方有一些习惯性的差别,尽管有时它们显得可以相互代替 | |
循环体处理中正确设置了循环终止标志了吗? |
| 如果循环体中没有任何操作改变循环推出标志,则会导致死循环的发生.这中情况有可能出现在循环体中的一些错误的条件判断下对循环退出标志进行设置. | |
尽量避免在循环体中的if处理分支中使用continue |
| 在循环体中的if处理分支中如果需要使用continue,建议使用else代替 | |
循环体退出出现多个出口时,每一个出口都是必须的并且保证了其正确性吗 |
| 循环体退出如果有多个出口,需要仔细考虑其必要性和退出循环的逻辑正确性 | |
要避免过深的循环嵌套 |
| 过深的循环嵌套会导致程序执行效率低下,且容易产生错误 | |
尽量能够使用std和boost标准库中循环方式 |
| 减少错误概率,提高可读性 | |
函数/方法 | 局部变量是否包含了数组或者大的数据结构 |
| 过大的局部变量(数组,结构,类)都可能造成堆栈溢出,因此原则上大于512个字节的局部变量都最好使用动态分配内存的方法解决 |
函数命名符合规范吗? |
| 如Get,Query,Set等函数前缀都有其约定用法,如果一个函数在实现Get的同时还完成了其它功能,那么它不应当仅仅取名为GetXXX.. | |
函数实现时对传入参数做了正确检查了吗? |
| 原则上应该对所有传入函数的参数都做合理性检查,至少应该使用断言进行检查. | |
函数所有出口都能够正确返回结果吗 |
| 当一个函数题出口存在多个时,程序是否保证了每一个出口都返回了正确的函数执行结果.. | |
使用缺省参数的方式来代替函数重载吗? |
| 通常情况下不建议使用缺省参数的方式来代替函数重载.这样会给程序的可读性和可扩展性带来不良影响. | |
是否尽量避免了函数和操作符重载? |
| 通常情况下不建议使用函数和操作符重载,这同样会给程序的可读性和可扩展性带来不良影响. | |
注释 | 每一个函数,类,文件在其头上都有一个符合规范的注释吗? |
| 规范化的函数,类,文件头注释,不仅可以自动生成详细设计文档,而且也可以引导编程者写出完备的注释. |
每一个变量和常量声明处都有注释吗? |
| 应该尽量载变量和常量的声明处加上注释,这样可以让程序变得容易维护 | |
代码实现和注释保持了一致性吗 |
| 每一个函数或类的注释头与具体实现保持了一致吗?在进行代码修改时,人们往往忘记了同步修改相关注释,导致代码的可读性变差 | |
代码中的注释是否有意义? |
| 在函数头的注释中把所有的输入参数罗列一遍,却不解释每个参数的含义 |