编程规范.doc_第1页
编程规范.doc_第2页
编程规范.doc_第3页
编程规范.doc_第4页
编程规范.doc_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

编程规范与原则 湘潭大学信息工程学院 作者:刘新Email:liuxin_ 版本号: 1.0 1. 导言1.1 为何需要编程规范 编程规范与惯例对于程序员来说非常重要,有以下几点原因:l 编码是程序员的职责,一个好的信息技术产品必然有高质量的代码,高质量的代码首先一点它必须遵守某种编程规范。l 一个软件整个生命周期内成本的80%用于维护。l 几乎没有一个软件在整个生命周期内全部由它的原始作者来维护。l 编程规范改善了软件的可读性,使工程师更加快速、彻底的理解新代码。l 如果你的源代码被作为产品发布,那么你必须保证它和其它产品一样很好的包装并保持整洁。l 大量数据表明,软件存在问题或者隐患,很大一部分是由于未遵守基本准则所致,如果能在l 项目早期明确规则,则会避免许多麻烦。 l 为了简化工作,每一个编写软件的人都必须遵守编程规范。每个人! 1.2 适用范围 本文阐述的编码规范主要使用在具备下面特性的软件: l 以C/C+为编程语言。l 资源受限的系统,对性能有较严格要求的的系统。本规范中每一条款都有一个执行等级,分为: l 必须代码无条件的满足必须等级的条款,不满足的代码必须得到修改,以满足相关的条款。 l 推荐条款非强制执行的,一般情况下遵照条款有助于改善代码的质量。 若不特别指出,所有条款执行”必须”等级。 2. 基本原则 本规范的基本目的是提高代码的可维护性。也就是说,代码必须是可读的、易于理解的、可测试的和可移植的。 2.1 所有的代码必须符合业界标准1、尽可能使用标准函数库,如 ANSI C和STL。 2、所有的函数原型必须符合ANSI 标准,单独在头文件中声明或者在源文件的预处理语句后声明,不要声明在函数内部;3、原型声明中的形参要有类型和名称;4、所有的参数定义必须写在圆括号中;5、函数有返回值,一定要写返回值类型,没有返回值,一定要写void;6、如果源程序中有main()函数,它必须是源程序中定义的第一个函数,返回值类型是int,要用return语句返回执行情况。2.2 保持代码简单直观1、 避免使用深度超过3 层以上的嵌套语句(如3重以上循环和3重以上的分支结构)。如碰上这种情况,请将内层语句写成函数形式。2、 避免编程语言中隐含或者晦涩的特性。直接表达你的意图。 3、 在一个表达式中,如果某变量使用了自加或自减运算符,该变量只允许出现一次。如下表达式绝不允许出现:k = i + i+;4、 规则3同样适用于函数调用时的参数传递,这样的调用不允许出现:callFun(i, i+);5、 一条语句只做一件事情,不要用逗号表达式来代替多条语句。6、 循环要完成的工作,写在循环体中,循环控制部分尽量简单。下面这种代码不允许出现:for(cx=x,cy=y; r=cx%cy; cx=cy,cy=r);while(scanf(%d,&n),n) ;7、尽量不要使用goto语句。goto语句只能在多重循环嵌套的最内层向最外层跳出时使用,且循环次数非常多(百万次级数以上)。2.3请及时更新旧代码 受产品的资金、时间、范围的约束,你可能写出能工作但结构不优美、执行效率不高的代码,这情有可原,但不要对这种代码置之不管。 2.4 保持良好的软件结构 一般情况下,好的软件结构具备如下特征: l 顶层函数的扇出较高 扇入一个函数被直接上级函数的数目,即有多少个函数直接调用它2 扇出 一个函数直接调用(控制)其它函数的数目 l 中层函数的扇出较少 l 底层函数则归入到公共模块中 2.5 预留调试接口,对可能存在的错误作出预防 3. 文件命名与组织 3.1扩展名表1 常用文件扩展名文件类型扩展名备注C源文件.c小写C+源文件.cpp小写C/C+头文件.h小写3.2. 常用文件名表2 常用文件名文件名称 用途Makefile Makefile 的首选名称。RELEASE程序发行说明,描述各个版本的主要更改、问题解决状况、尚未解决的问题等等README总结项目目录的内容ChangeLog代码修改记录,详细描述对每个源文件所做的修改,最好精确到函数级别4. 代码结构 4.1 文件头 文件头是嵌入在 C/C+头文件或源文件中,在文件首部的注释块,一般包含如下信息: l 公司或组织的名称 l 地址 l 版权说明 l 开发人员 l 模块目的/功能 l 文件版本 l 修改日志 4.2 C/C+头文件 头文件的布局如下: 文件头 版本历史 常量定义 全局宏定义 是否在头文件包含文件头,这有些争议,有些头文件较简单,可不必包含文件头。但一般说来,公共头文件(接口/原型)需要带有文件头。 4.3 C/C+源文件 源文件也即实现文件,其布局: 文件头 版本历史 #include 区 #define 区 宏定义区(Macros) 本地数据类型定义区(Local data types) 本地变量区 (Local variables) 本地表 (Local tables) 本地函数原型 (Local function prototypes) 全局函数(Global functions) 局部函数(Local functions) 5. 排版 5.1 代码行宽度 推荐每行的代码宽度限制在 80 个字符内。80 个字符限制是由于旧显示器的约束,可视范围只有80 个字符。较长的语句(80 字符),要分成多行书写,,表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。 推荐:太长的表达式可以分成多个较短的表达式来书写。5.2 TAB字符的使用请将编辑器的TAB字符占位设置为4个空格。 5.3 缩进函数、结构、循环、判断等语句都需要采用缩进,缩进请使用一个TAB(4 个空格)。5.4 空行相对独立的程序块之间、变量说明之后必须加一个空行。 但不要随意添加无谓的空行。例如,下面的写法不正确:void function1() int var1,var2; var1 = 1; var2 = 2; 正确的书写方法是: void function1() int var1, var2; var1 = 1; var2 = 2; 5.5 不允许把多个短语句写在一行中 示例:如下例子不符合规范 rect.length = 0; rect.width = 0; 应如下书写 rect.length = 0; rect.width = 0; 5.6 添加空格在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如),后不应加空格。示例如下: 1、逗号、分号只在后面加空格int a, b, c; 2、比较操作符, 赋值操作符=、 +=, 算术操作符+、 %, 逻辑操作符&、 &,位域操作符= MAX_TIME_VALUE) a = b + c; a *= 2; a = b 2; 3、!、+、-、&(地址运算符)等单目操作符前后不加空格。 *p = a; / 内容操作*与内容之间 flag = !isEmpty; / 非操作!与内容之间 p = &mem; / 地址操作& 与内容之间 i+;/ +,-与内容之间 4、-、.前后不加空格。 p-id = pid; / -指针前后不加空格 5、 if、for、while、switch 等与后面的括号间应加空格,使 if 等关键字更为突出、明显。 if (a = b & c d) 5.7 对于赋值语句,等号和数值保持垂直对齐。(推荐)示例: DispSegTblIx = 0; DispDigMsk = 0x80; DispScale = 1.25; 6. 注释 6.1 每一个注释都必须有用. 6.2 对于函数要给出必要的注释必须注释出::函数的名称、功能、入口参数、出口参数、返回值、调用说明。除非有把握使用英语明确表达你的用意。一般情况下使用中文。/* * sample_func summary this function * param1: description of param1 * param2: description of param2 * Detail descript the usuage of sample_func. */ int sample_func(int param1, int param2); 上面的例子中,每一行前面的那个*号,由编辑器自动添加,如果你的编辑器不会自动添加,可以不必添加。6.3 注释的修改边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。 6.4 尽可能使用尾部注释 示例: void ClkUpdateTime (void) if (ClkSec = CLK_MAX_SEC) / Update the secondsClkSec = 0; if (ClkMin = CLK_MAX_MIN) /Update the minutesClkMin = 0; if (ClkHour = CLK_MAX_HOURS) / Update the hours ClkHour = 0; 6.5 注释的格式尽量统一尾部注释建议使用“/”,头部使用块注释“/* */” 7. 标识符命名约定 7.1 一般约定1、用#define或者const定义的符号常量所有字符都必须大写。2、局部变量、成员变量和函数名采用驼峰规则,除第一个单词的首字母小写外,其它单词的首字母大写。3、类名采用驼峰规则,所有单词首字母都要大写。4、全局变量要以下划线作为首字符。(但尽量不要使用全局变量)5、所有用户自定义标识符尽量以有意义的单词组合作为名称。6、循环计数器可以使用i,j,k这类短名称7、指针类型以p开头。7.2 缩写与助记符太长的单词可以使用缩写或者助记符形式,基本规则是取其中的3-4个字母,具体是:1、首尾两个字母,中间取每个音节的首个字母(1-2个);2、或者取最前面的3-4个字母;3、一般不取元音字母;4、如果已经有了公认的缩写形式,则以公认的形式为准,不受上面3条规则限制。表3 常用单词缩写表单词缩写单词缩写ArgumentArgBuffer BufClearClrClock ClkCompare CmpConfiguration CfgContext CtxControlCtlDelay DlyDevice DevDisable DisDisplay DispEnable EnErrorErrFunction FnctHexadecimalHexHigh Priority Task HPTI/O System IOSInitialize InitMailbox MboxManager MgrManualManMaximum MaxMessage MsgMinimum MinMultiplex MuxOperationg System OSOverflow OvfParameter ParamPointer PtrPreviousPrevPriority PrioRead RdReadyRdyRegister RegSehedule SchedSemaphore SemStack StkSynchronize SyncTimer TmrTrigger TrigWrite Wr8. 变量使用 1、尽可能少地定义全局变量;2、局部变量与全局变量不要同名;3、严禁使用未经初始化的变量作为右值;9. 函数设计和使用9.1 函数设计1、明确函数功能,精确(而不是近似)地实现函数设计。 2、尽量不使用递归函数,尽可能从算法上消除递归,能用迭代的,坚决不能使用递归。如果不能消除递归,则用自行管理堆栈的形式来消除形式上的递归。3、函数的规模尽量限制在 200 行以内(不包括注释和空格行)。4、一个函数执行一个任务或功能,一个复杂的功能可由多个功能单一的函数实现。 5、函数的功能是可以预测的,也就是只要输入数据相同就应产生同样的输出。除非该函数已经明确表示使用了随机算法。说明:带有内部“存储器”的函数的功能是不可预测的,因为它的输出可能取决于内部存储器(如某标记)的状态。这样的函数即不易于理解也不利于测试和维护。 6、尽量不要编写依赖于其他函数内部实现的函数。此为函数独立性的基本要求。7、如果多段代码重复做同一件事情,那么在函数的划分上可能存在问题。 说明:若此段代码各语句之间有实质性关联并且是完成同一件功能的,那么可考虑把此段代码构造成一个新的函数。8、 功能不明确较小的函数,特别是仅有一个上级函数调用它时,应考虑把它合并到上级函数中,而不必单独存在。 说明:模块中函数划分的过多,一般会使函数间的接口变得复杂。所以过小的函数,特别是扇入很低的或功能不明确的函数,不值得单独存在。 9、设计高扇入、合理扇出(小于 7)的函数。 扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,如总是1,表明函数的调用层次可能过多,这样不利程序阅读和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。函数较合理的扇出(调度函数除外)通常是3-5。扇出太大,一般是由于缺乏中间层次,可适当增加中间层次的函数。扇出太小,可把下级函数进一步分解多个函数,或合并到上级函数中。当然分解或合并函数时,不能改变要实现的功能,也不能违背函数间的独立性。 扇入越大,表明使用此函数的上级函数越多,这样的函数使用效率高,但不能违背函数间的独立性而单纯地追求高扇入。公共模块中的函数及底层函数应该有较高的扇入。10、函数除了有正常的返回值,也应该有表示出错情况的返回值。如果二者不可兼得,应该使用异常机制。9.2函数调用 1、对于所调用函数的错误返回码要仔细、全面的处理。2、应明确规定对接口函数参数的合法性检查由函数的调用者还是由接口函数本身负责。缺省是由函数编写者负责,除非函数内部无法判断参数的合法性(比如指针所指向的空间大小,这时调用者必须保证空间足够)。3、非调度函数应减少或限制控制参数,尽量只使用数据参数。 说明:本建议目的是防止函数间的控制耦合。调度函数是指根据输入的消息类型或控制命令,来启动相应的函数,而本身并不完成具体功能。控制参数是指改变函数功能行为的参数,即函数要根据此参数来决定具体怎样工作。非调度函数的控制参数增加了函数间的控制耦合,很可能使函数间的耦合度增大,并使函数的功能不唯一。 示例:如下函数构造不太合理 int add_sub( int a, int b, unsigned char add_sub_flg ) if (add_sub_flg = INTEGER_ADD) return (a + b); else return (a - b); 更好的做法是分为两个函数 int add( int a, int b ) return (a + b); int sub( int a, int b ) return (a + b); 4、在调用函数填写参数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换,因为数据类型转换或多或少存在危险(建议:将编译器的所有警告开关全部打开,让编译器帮助发现此类危险)。10. 宏 可以使用宏来定义符号常量,但应该尽量减少用宏来定义表达式,切不可使用宏来代替函数。定义表达式时,要使用完备的括号。 11. 头文件11.1 防止重复包含为防止重复包含,请在头文件加上条件INCLUDE。 示例: #ifndef _LINUX_FILE_H #define _LINUX_FILE_H #include #include #include #endif 11.2 仅引用需要的头文件 当模块的实现依赖于其他模块时,要这样做:尽量在 C/C+源文件手工引用多个头文件,仅引用你需要调用的头文件。 而不要这样做:把多个头文件包含在一个头文件中,源文件仅包含这一个头文件。12. 可测性 12.1 调试信息的控制要有一套统一的为集成测试与系统联调准备的调测开关及相应打印函数,并且要有详细的说明。示例,以下使用DEBUG作为调试开关,输出调试信息#ifdef DEBUG #define DPRINTF(s) PRINTF(s) #else #define DPRINTF(s) #endif 如果要将调试开关打开,只需要传递给编译器”-DDEBUG”的标记。测试代码部分应作为 (模块中的) 一个子模块, 以方便测试代码在模块中的安装与拆卸(通过调测开关)。 12.2 调试信息的格式调测打印出的信息串的格式要有统一的格式。信息串中至少要有所在模块名(或源文件名)及行号。 说明:统一的调测信息格式便于分析,特别是用程序来辅助分析。 12.3 使用断言断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告),它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。实际应用时,可根据具体情况灵活地设计断言。 正式软件产品中应把断言及其他调测代码去掉(即把有关的调测开关关掉)。在软件系统中设置与取消有关测试手段,不能对软件实现的功能等产生影响(即有测试代码的软件和关掉测试代码的软件,在功能行为上应一致)。 13. 质量保证 13.1 代码质量保证优先原则 1、正确性,指程序要实现设计要求的功能。 2、稳定性、安全性,指程序稳定、可靠、安全。 3、可测试性,指程序要具有良好的可测试性。 4、规范/可读性,指程序书写风格、命名规则等要符合规范。 5、全局效率,指软件系统的整体效率。 6、局部效率,指某个模块/子模块/函数的本身效率。 7、个人表达方式/个人方便性,指个人编程习惯。13.2 只引用属于自己的存贮空间若模块封装的较好,那么一般不会发生非法引用他人空间的情况。 13.3 防止引用已经释放的内存空间在实际编程过程中, 稍不留心就会出现在一个模块中释放了某个内存块 (如 C 语言指针),而另一模块在随后的某个时刻又使用了它。要防止这种情况发生,除了多测试,别无办法。13.4 防止内存泄漏 函数中分配的内存,在函数退出之前要释放。用malloc函数分配的内存,要用free释放;用new分配的内存,要用delete释放。为了最大程度上避免内存泄漏的出现,推荐:1、 如果动态

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论