1. 文件结构
1-1. 版权和版本声明:版权和版本声明位于头文件和定义文件的头,主要内容有:
(1)版本信息;
(2)文件名称,标识符,摘要;
(3)当前版本号,作者/修改者,完成日期;
(4)版本历史信息。
/******************************************************************************
Copyright(c) 2001,公司名称
文件名称:filename.h
(作者:) (版本:) (完成日期:)
摘 要: 简要描述本文件的内容
修改记录:
修改时间: 修改者 :
修改内容:
*******************************************************************************/
示例1-1 版权和版本的声明
1-2.头文件结构: 头文件结构由三部分组成:
(1)头文件开头处的版权和版本声明;
(2)预处理快;
(3)函数和类结构声明等。
1-3.为了防止头文件被重复引用,应当用#ifndef/#define/#endif结构产生预处理块。
1-4.用#include<filename.h>格式来引用标准库的头文件。
1-5.用#include “filename.h”格式来引用非标准库的头文件。
1-6.头文件只存放“声明”而不存放“定义”。
1-8.不提倡使用全部变量。
1-9.定义文件结构:定义文件有三部分内容:
(1)定义文件开头处的版权和版本声明(参见示例1-2)
(2)对一些头文件的引用
(3)程序的实现体(包括数据和代码)
1-10.目录结构:
(1)如果一个软件的头文件数目比较多(如超过10个),通常应将头文件和定义
文件分别存放于不同的目录,以便于维护。
(2)如果某些头文件是私有的,它不会被用户的程序直接引用,则没必要公开其
声明,为加强信息隐藏,这些私有的头文件可以和定义文件存放于同一目录。
2. 排版
2-1.在每个类声明之后、每个函数定义结束之后都要加空行。
2-2.相对独立的程序块之间,变量说明后必须加空行。
2-3.一行代码只做一件事情,如只定义一个变量,或只写一条语句。
2-4.if、for、while、do等语句自占一行,不论执行语句有多少都要加{}。
2-5.尽可能在定义变量的同时初始化该变量(就近原则)。
2-6.关键字之后要留空格。if,for,while等之后应留一个空格再跟’(’,以突出关键字。
2-7.如果’;’不是一行的结束符号,其后要留空格,如for (init; cond; update)。
2-8.赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符等二元
操作符的前后应加空格。
2-9.对于表达式比较长的for语句和if语句,为了紧凑起见可以适当去掉一些空格,
如:for (i=0; i<10; i++)和if((a<=b) && (c<=d))。
2-10.’{’和’}’应独占一行并且位于同一列,同时与引用它的语句左对齐。
2-11.长表达式(80字符)要在低优先级操作符处拆分成新行,操作符放在新行之首,
拆分出的新行要适当的缩进。
3. 注释
3-1.一般情况下,源程序有效注释量必须在20%以上。
3-2.函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、
调用关系。
/******************************************************************************
函数名称:
函数功能: 函数功能及性能描述
调用关系: 被本函数调用的函数
被调关系: 调用本函数的函数
输入参数: 包括每个参数的作用、取值说明及参数间关系
输出参数: 对输出参数的说明
返回值 : 函数返回值说明
******************************************************************************/
函数头注释
3-2.边写代码边注释,修改代码同时修改相应的注释。
3-3.注释应当准确、易懂,防止注释有二义性。
3-4.尽量避免在注释中使用缩写,特别是不常用缩写。
3-5.注释的位置应与被描述的代码相邻,可放在代码的上方或右方,不可放在下方。
3-6.如果变量、常量或者数据结构的命名不是充分注释的,必须要加注释。
3-7.全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它
以及存取时注意事项等等说明。
3-8.当代码比较长时,特别是有多重嵌套时,应当在一些段落的结束处加注释。
4. 命名规则
4-1.标识符应当清晰明了且易于拼读,应使用完整的单词或大家基本可以理解的缩写。
常用缩写:temp---tmp, flag---flg, statistic---stat,increment---inc, message---msg
4-2.标识符最好采用英文单词或者组合,切忌使用汉语拼音。
4-3.标识符的长度最好在8-20之间。
4-4.命名规则尽量与所采用的操作系统或开发工具的风格一致。
例如,windows通常采用大小写混排的方式,unix通常采用小写加下划线的方式。
4-5.程序中不要出现仅靠大小写区分的相似标识符。
4-6.程序中不要出现标识符完全相同的局部变量和全部变量。
4-7.变量的名字应当使用“动词”或者“形容词+名词”。
4-8.用正确的反义词命名具有互斥意义的变量或相反动作的函数等。
常用反义词组:add/remove, begin/end, create/destroy,insert/delete, first/last,
get/release,increment/decrement, put/get, add/delete, lock/unlock, open/close, min/max,
old/new, start/stop, next/previous,source/target, show/hide, send/receive, cut/paste,
source/destination, up/down。
4-9.在同一个软件产品内,应规划好接口部分标识符(变量、结构、函数及常量)的命名,
建议在之前加上“模块”标识等。
4-10.常量全用大写字母,用下划线分割单词。
4-11.建议在静态变量前加前缀s_,全局变量前加前缀g_,结构体数据成员前加前缀
m_。
4-12.避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理
意义的常量,不应直接使用数字,必须用有意义的枚举或者宏来替代。
5. 常量、变量、结构
5-1.去掉没必要的公共变量。
5-2.明确公共变量与操作此公共变量的函数或过程的关系,如访问、修改及创建等。
5-3.严禁使用未经初始化的变量作为右值。
5-4.构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数值访问公共
变量。
5-5.结构功能要单一,是针对一种事物的抽象,不要设计面面俱到、非常灵活的数据
结构。
5-6.不同结构间的关系不要过于复杂,若两个结构关系复杂、密切,应合为一个结果。
5-7.结构中元素个数应适中。若结构中元素个数过多可考虑依据某种原则把元素组成
不同的子结构。
5-8.仔细设计结构中元素的布局与排列顺序,使结构容易理解、节省占用空间。
5-9.结构的设计要尽量考虑向前兼容和以后的版本升级,并为某些未来可能的应用保留
余地(如预留一些空间等)。
5-10.合理设计数据并使用自定义数据类型,避免数据间进行不必要的类型转换。
5-11.当声明用于分布式环境或不同CPU间通信环境的数据结构时,必须考虑机器的
字节顺序、使用的位域及字节对齐等问题。
5-12.需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义文件的头部,
为便于管理,可将不同模块的常量集存放在一个公共的头文件中。
5-13.如果一常量与其他常量密切相关,应在定义中包含这种关系,而不是给出孤立的
值。
6. 函数和过程
6-1.参数的书写要完整,不要只写参数的类型而省略参数的名字。
6-2.参数命名要恰当,顺序要合理。应将目的参数放在前面,源参数放后面。
6-3.如果参数是指针,且仅作输入用,则应在类型前加const。
6-4.避免函数有太多参数,参数个数尽量控制在5个以内。
6-5.避免使用类型和数目不确定的参数(可变参数)。
6-6.不要省略返回值的类型。
6-7.函数名字与返回值类型在语义上不要冲突。
6-8.不要将正常值和错误标志混在一起返回。
6-9.有时函数原本不需要返回值,但为增加灵活性可以附加返回值(如支持链式表达)。
6-10.在函数体的“入口处”,对参数的有效性进行检查。
6-11.在函数体的“出口处”,对return语句的正确性和效率进行检查。
6-12.函数功能要单一,不可设计多用途函数。
6-13.函数体规模要小,尽量控制在200行代码之内(不包括注释和空行)。
6-14.尽量避免函数带有“记忆”功能(少用static局部变量)。
6-15.用于出错处理的返回值一定要清楚,让使用者不容易忽视或误解错误情况。
6-17.明确函数的功能,精确(而不是近似)地实现函数设计。
6-18.使用全局变量时,需考虑是否应该通过关中断等手段对其加以保护。
6-19.防止将函数的参数作为工作变量。
6-20.为简单功能编写函数。
6-21.非调度函数应减少或防止控制参数,尽量只使用数据参数。
6-22.在调用函数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换。
6-23.避免函数中不必要语句,放在程序中的垃圾代码,防止把没有关联的语句放到
一个函数中。
6-24.功能不明确较小的函数,特别是仅有一个上级函数调用它时,应考虑把它合并到
上级函数中,而不必单独存在。
6-25.设计高扇入、合理扇出(小于7)的函数。
说明:扇出是指一个函数直接调用其它函数的数目,而扇入是指由多少上级函数
调用它。
6-26.减少函数本身或者函数间的递归调用。
6-27.仔细分析模块的功能及性能需求,并进一步细分,同时若有必,画出有关数据流
图,据此来进行模块的函数划分与组织。
6-28.改进模块中函数的结构,降低函数间的耦合度,并提高函数的独立性以及代码
可读性、效率和可维护性。
6-29.避免使用BOOL参数。
6-30.当一个过程(函数)中对较长变量(一般是结构的成员)有较多引用时,可以用一个
意义相当的宏替代。
7. 可测性
7-1.编程的同时要为单元测试选择恰当的测试点,并仔细构造测试代码、测试用例,同时给出明确的注释说明。测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过测试开关)。
7-2.在进行集成测试/系统联调之前,要构造好测试环境、测试项目及测试用例,同时仔细分析并优化测试用例,以提高测试效率。
8. 程序效率
8-1.编程时要经常注意代码的效率。
8-2.在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。
8-3.局部效率应为全局效率服务,不能因为提高局部效率而对全局效率造成影响。
8-4.通过对系统数据结构的划分与组织的改进及对程序算法的优化来提高空间效率。
8-5.循环体内工作量最小化。
8-6.仔细分析有关算法,并进行优化。
8-7.在多重循环中,应将最忙的循环放在最内层。
8-8.避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中。
8-9.仔细考查、分析系统及模块处理输入(如事务、消息等)的方式,并加以改进。
8-10.对模块中函数的划分及组织方式进行分析、优化,改进模块中函数的组织结构,
提高效率。
8-11.尽量用乘法或其它方法代替除法,特别是浮点运算中的除法。
9. 质量保证
9-1.在软件设计过程中构筑软件质量。
9-2.代码质量保证优先原则
(1)正确性,指程序要实现设计要求的功能。
(2)稳定性、安全性,指程序稳定、可靠、安全。
(3)可测试性,指程序要具有良好的可测试性。
(4)规范/可读性,指程序书写风格、命名规则等要符合规范。
(5)全局效率,指软件系统的整体效率。
(6)局部效率,指某个模块/子模块/函数本身的效率。
(7)个人表达方式/个人方便性,指个人编程习惯。
9-3.防止引用已经释放的内存空间。
9-4.过程/函数中分配的内存,在过程/函数退出之前要释放。
9-5.防止内存操作越界。
9-6.认真处理程序所能遇到的各种出错情况。
9-7.系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。
9-8.系统运行之初,要对加载到系统中的数据进行一致性检查。
9-9.严禁随意更改其它模块或系统的有关设置和配置。
9-10.不能随意更改其它模块的接口。
9-11.充分了解系统的接口之后,再使用系统提供的功能。
9-12.编程时,要防止差1错误,如<=误写成<
9-13.要时刻注意易混淆的操作符,当遍完程序后,应从头至尾检查一遍这些操作符。
9-14.f尽量加else分支,switch语句必须有default分支。
9-15.不要滥用goto语句。
9-16.使用变量时要注意其边界值的情况。
9-17.为用户提供良好的接口界面,使用户能较充分地了解系统内部运行状态及有关系统出错的情况。
9-18.系统应具有一定的容错能力,对一些错误事件(如用户误操作等)能进行自动补救。
10. 代码编辑、编译、审查
10-1. 通过代码走读及审查方式对代码进行检查。
10-2. 仔细地对待编译器发出的所有警告。
10-3. 编写代码时要注意随时保存,并定期备份。
10-4. 合理地设计软件系统目录,方便开发人员使用。
10-5. 某些语句经编译后产生告警,但如果你认为它是正确的,那么应通过某种手段去掉告警信息。
11. 代码测试、维护
11-1.单元测试要求至少达到语句覆盖。
11-2.单元测试开始要跟踪每一条语句,并观察数据流及变量的变化。
11-3.清理、整理或优化后的代码要经过审查及测试。
11-4.代码版本升级要经过严格测试。
11-5.使用工具软件对代码版本进行维护。
11-6.正式版本上任何修改都应有详细的文档记录。
11-7.发现错误立即修改,并且要记录下来。
11-8.仔细设计并分析测试用例,使测试用例覆盖尽可能多的情况,以提高测试用例的效率。
11-9.尽可能模拟出程序的各种出错情况,对出错处理代码进行充分的测试。
11-10.仔细测试代码处理数据、变量的边界情况。
11-11.保留测试信息,以便分析、总结经验及进行更充分的测试。
11-12.不应通过“试”来解决问题,应寻找问题的根本原因。
11-13.对自动消失的错误进行分析,搞清楚错误是如何消失的。
11-14.明确模块或函数处理哪些事件,并使它们经常发生。
11-15.测试时应设法使很少发生的事件经常发生。
11-16.坚持编码阶段就对代码进行彻底的单元测试。
12. 宏
12-1.用宏定义表达式时,要使用完备的括号。
12-2.将宏所定义的多条表达式放在大括号{}中。
12-3.使用宏时,不允许参数发生变化。