编码规范(CC++).doc_第1页
编码规范(CC++).doc_第2页
编码规范(CC++).doc_第3页
编码规范(CC++).doc_第4页
编码规范(CC++).doc_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

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

文档简介

目录C & C+编码规范31.导言31.1.适用范围31.2.执行等级32.文件命名及文件结构33.排版风格54.注释风格65.命名规则76.基本编码原则86.1.正确性原则86.2.可维护性原则:96.3.效率原则106.4.可移植原则106.5.可测试原则116.6.编译原则126.7.其他127.代码实现的流程127.1.需求理解和详细设计127.2.代码编写127.3.代码检查137.4.代码提交13C & C+编码规范1. 导言1.1. 适用范围l 以C/C+为编程语言l 资源受限系统1.2. 执行等级本规范中每一条款都有一个执行等级,分为: 【必须】 代码无条件的满足必须等级的条款,不满足的代码必须得到修改,以满足相关的条款。 【推荐】 条款非强制执行的,一般情况下遵照条款有助于改善代码的质量。若不特别指出,所有条款执行【必须】等级。2. 文件命名及文件结构2.2.1. 文件命名文件名由单个或者多个有意义,能“体现该文件功能”的单词、单词缩写组成。C+文件:l 每个单词的首字母必须大写;l 单词之间不用下划线分割;l 其文件名尽量和类名同名。l 【推荐】原则上一个头文件中只包含一个类的声明C文件:l 模块名+下划线+有意义的单词组合,l 模块名小写;l 单词组合的首个单词的首字母小写,其它的单词的首字母大写; 2.2. 文件头文件头是嵌入在C/C+头文件或源文件中,在文件首部的注释块,一般包含如下信息:l 版权说明l 模块目的/功能2.3. C/C+头文件除文件头以外,C/C+代码的头文件中,还需按以下顺序进行布局:l 防止头文件重复包含的宏例如,头文件名为AbcDef.h,则该宏形如:#ifndef _ABCDEF_H_#define _ABCDEF_H_#endifl #include 区引用的头文件,按如下顺序 标准库/STL 头文件 第三方代码 头文件 自有代码 头文件,并且自有代码头文件的第一行必须是#include 该头文件为全局性头文件,用于包含一些全局设置、调试开关、打印开关等内容。l 常量定义l 全局宏定义l 类声明(C+)或全局数据类型声明(C)l 外部引用全局变量l 全局函数原型声明(C)l C头文件,需要定义extern “C”2.4. C/C+源文件源文件也即实现文件,其布局方式为:l 文件头l #include 区,按如下顺序: 标准库/STL 头文件 第三方代码 头文件 自有代码 头文件l #define 区l 本地数据类型定义区l 本地变量区 l 本地表 l 类的成员函数(C+)l 本地函数原型 (C)l 全局函数(C)l 本地函数(C)2.5. C+类声明的基本布局方式l 友元声明l 前向类声明l 公有方法声明l 保护方法声明l 私有方法声明l 保护成员声明l 私有成员声明2.6. 文件的目录结构l 文件应按模块进行分目录放置l 头文件和实现文件应该在不同的目录中,按模块分别放置l 第三方代码应该放置到单独目录中,并保持其原始结构3. 排版风格排版风格约定的基本原则是使程序易读易懂,一目了然,以利于代码阅读。3.3.1. 使用缩进程序块采用缩进风格编写,缩进为4个空格位。缩进不使用TAB。3.2. 在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格; 进行非对等操作时,后不应加空格。例如:l 分号、逗号只在后面加空格l 双目操作符如“+”,“-”,“”,“”等的前后加空格l 单目操作符如*、!、等前后均不加空格l -、.前后不加空格3.3. 任何需要空白的地方,只允许加一个空格符号3.4. 使用,且仅使用一行空白行来区分具有相对完整的逻辑意义的两个代码块,如循环体前后、分支控制语句前后等。3.5. 一行代码中只包含一条语句,不要将多条语句写到一行。例如以下格式均不符合此规范:if(pUserCR = NULL) return;rect.length = 0 ; rect.width = 0 ; rect.length = width = 0;3.6. 单条语句尽量简洁,不要包含过多的操作。以下示例代码不符合本条规范:flag = ( sqr( pointer-count+ ) * sin( -pointer-angle ) 0) ? (pointer=NULL):(pointer); 应该修改为:result = sqr( pointer-count+ ) * sin( -pointer-angle );flag = result 0 ? (pointer = NULL) : (pointer);3.7. 单条语句较长时,可分成多行书写;新行使用一个缩进单位,并且操作符出现在新行行首。例如:if( rect.x 0 & rect.y 0 & rect.width 0 & rect.height 0 )3.8. 使用#define定义宏时,使#define的各个字段对齐,例如:#define MAX_LEN 5#define MAX_PATH 5#define MAX_PATH_LEN 53.9. 对于多个变量同时赋值时,使多个赋值语句间的“=”符号对齐,例如:rect.x = 0;rect.y = 0;rect.width = 0;rect.height = 0;3.10. 多个类型的操作符出现在同一条语句中,使用()来给出优先级。如:if( (year % 4) = 0 & (year % 100) != 0 & (year % 400) = 0)3.11. if-else, while, do-while, for等语句后必须使用将代码块进行包围。例如:if( ret ) doSomething();或者while( true = ret ) ret = doSomething();4. 注释风格注释的原则是有助于对程序的阅读理解,注释不宜太多也不能太少,太少不利于代码理解,太多则会对阅读产生干扰,因此只在必要的地方才加注释,而且注释要准确、易懂、尽可能简洁。注释量一般控制在30%到50%之间。4.4.1. 采用Doxygen的注释风格4.2. 类的注释方式:/* 简要说明,尽量用一句话描述 * 详细说明类的职责,使用场景 * sa 相关的类 */class A4.3. 函数、方法的注释方式:/* 简要说明,尽量用一句话描述 * 详细说明函数的使用场景,预期结果等 * param name 参数说明 * return 返回值说明 * attention 使用中的注意事项 * sa 相关的函数或者类 */4.4. 成员变量的注释方式class Apublic:int mCount; /* 作用说明 */ 4.5. C代码的头文件必须添加针对该文件用途的注释4.6. 类、结构、全局变量、局部静态变量、枚举类型等必须添加详细的注释说明用途和使用方法。4.7. C代码中,模块的接口函数必须添加注释说明用途和使用方法。4.8. C+代码中,类的Public和Protected的方法和成员必须添加注释说明用途和使用方法。4.9. 【推荐】给所有的函数、方法添加注释说明用途和使用方法。4.10. 【推荐】对于比较复杂的函数和方法,在注释中添加示例代码说明其使用场景和使用方法。4.11. 在必要的地方必须有注释,注释要准确、易懂、简洁,还必须说明代码中不能表达的信息。例如:例如如下注释意义不大。 /* 如果receiveFlag为 TRUE */ if ( receiveFlag = TRUE ) 而下面的注释则给出了额外有用的信息。 /* 如果mtp 从连接处获得一个消息*/ if ( receiveFlag = TURE) 4.12. 注释应与其描述的代码相近,对代码的注释应放在其上方或右方4.13. 保证注释和代码的一致性,更新代码时必须同时更新对应的注释。4.14. 【推荐】对于需要注释的代码,优先考虑将该代码块抽取为一个函数,使用函数名来表达需要注释的内容,实现代码的自解释。4.15. switch-case语句中,对于没有break的case项,要加上注释说明。4.16. 不允许使用注释或者#if 0等方式保留无用或暂时无用代码4.17. 不允许在注释中保留日期、个人信息等与代码含义无关内容,例如:/* Modified by Paul, 2008/09/08 */正确的方式应该是:/* Changed the way of sorting from bubble to quick sort */修改日期和修改者等信息可以使用版本控制工具查看,无需在代码中注明。5. 命名规则5.5.1. C函数命名规则:模块名_函数名模块名使用该模块的名称或缩写,一般为3-5个字符,全部大写。函数名可采用一个或多个单词,单词之间无分隔符,首单词小写,其余单词首字母大写。推荐采用“动词+名词”的方式来命名函数。如: MEM_removeUnusedBlock(); 如果产品本身是提供给其他方使用的库,则接口前还可以加上产品缩写,例如:XF_MEM_removeUnusedBlock();5.2. 类命名规则l 所有单词的首字母为大写;l 单词之间不用下划线分割l 类的命名推荐用名词或形容词名词的形式。l 充分反映该类的职责或角色例如:class ResourceManagerclass ManagedMemPooll 类名前不使用前缀来标识模块或者产品,需要时可使用命名空间namespace来体现。l 【推荐】父类和子类的名字之间应具有一定的关联性,以体现这种继承关系。例如:class ImageResourceManager : public ResourceManager 5.3. 类方法命名规则l 采用“动词+名词”方式命名l 首单词全部小写,其余单词首字母大写l 命名必须反映该方法的作用和用途5.4. 结构命名规则l 同类命名规则5.5. 一般变量命名规则l 使用一个或多个能够反映该变量职责和用途的单词l 首单词全部小写,其余单词首字母大写l 命名必须反映该变量的用途,不允许使用i, j, k, temp 等无意义的单词。5.6. 类成员变量命名规则l 同一般变量命名规则l 变量名前加m以示和一般变量的区别例如:int mMaxIndex;5.7. 全局变量命名规则l 同一般变量命名规则l 变量名前加g以示和一般变量的区别5.8. 宏命名规则l 使用一个或者多个能够反映该宏职责和用途的单词l 单词全部大写,使用下划线_进行分割5.9. 常量命名规则l 同宏命名规则5.10. 函数/方法参数命名规则l 同一般变量命名规则5.11. 枚举和枚举成员命名规则l 枚举类型各单词均为大写,并使用下划线_分割l 枚举成员命名同枚举类型l 所有枚举成员第一个单词相同,并且该单词能大致区分该成员所属的枚举类型5.12. 避免在命名中出现含义不明确的数字,尽量使用含义更明确的单词。例如:int maxNumber1, maxNumber2;以上两个变量含义不够明确,读者无法从1或者2中读取有效的信息,无法区分两个变量的区别。将上述变量名改为以下名称则更有助于理解。int previousMaxNumber;int currentMaxNumber;5.13. 尽量避免在不同作用域中的重名,以免发生误解。例如,父类中某个成员名为mMaxNumber,则子类中不应该再使用这个名字。5.14. 避免过于相似的名字,如Function和function。5.15. 命名中可以使用缩写,缩写的首字母大写,其余字母小写。例如Global System For Mobile Communication的缩写为GSM,出现在标示符中则应为Gsm。例如:GsmSymbol。缩写应只使用约定俗成的、无二义性的缩写形式,以不造成歧义和理解上的困难为原则。若有必要,可在设计文档或者头文件注释中对编码中需要用到的缩写和术语进行说明。6. 基本编码原则6.6.1. 正确性原则程序首要的任务是执行正确,以下规则有助于保证程序的正确:6.1.1. 【推荐】熟悉并使用标准C+规范中所提供的工具STL,不要自己实现STL中已经提供的功能。6.1.2. 【推荐】C+代码操作字符串时,尽量使用STL的string和wstring6.1.3. 不在C+代码中使用malloc,free,而是使用new,delete6.1.4. 【推荐】不在C+代码中使用CRTL函数6.1.5. 变量定义时,必须进行初始化,严禁使用未经初始化的变量6.1.6. 一行中仅允许定义一个变量6.1.7. 【推荐】使用较大的局部变量(2K以上)时应谨慎。应声明成静态类型(static)或者采用动态分配,避免占用太多的堆栈空间。嵌入式系统中,较大的堆栈空间可能导致堆栈溢出,出现不可预知的软件故障。6.1.8. 对于大对象的传递,使用引用传递(指针、引用)的方式而不是值传递以减少对象拷贝过程中可能发生的错误。6.1.9. 避免使用goto,复杂的错误处理情况例外6.1.10. 减少没必要的指针使用,特别是较复杂的指针,如指针的指针、数组的指针,指针的数组,函数的指针等。6.1.11. switch语句的程序块中必须有default语句。6.1.12. 对于函数的参数和返回值中的指针,若其指向的对象不需要或不允许修改,则必须使用const修饰符进行修饰,以保证其不会被意外修改。例如:const char* getWindowTitle();void setWindowTitle(const char* newTitle);6.1.13. 类成员中的方法,若该方法不会修改该类的状态,必须使用const进行修饰。例如:class Window int getChildrenNo() const;6.1.14. 不允许类中存在公有成员变量,外部必须访问的,使用get/set方法进行访问。6.1.15. 【推荐】在控制语句中,使用一个变量和常量进行是否相等的比较时,将常量放到=符号的前面,而将变量放到后面,以防止发生偶然性错误。例如:if( 0 = value) ;6.1.16. 对所调用的函数,有返回值的必须要进行仔细、全面地处理。6.1.17. 声明函数原型时,对于数组型参数,不要声明为指针,维护函数接口的清晰性。6.2. 可维护性原则:代码必须具有一定的可维护性,以满足在将来发生变化时,便于根据新的变化进行功能增加或重构等工作,具有可维护性的代码必须是清晰易读,不容易导致人误解的,因为维护代码者很可能不是代码作者。以下规则有助于增加代码的可维护性6.2.1. 不允许在代码中出现数字(Magic Number),必须以宏或者常量的形式来替换。6.2.2. 不出现重复代码,当有逻辑相同或者类似的代码出现时,尽量使其复用。可采用的手段有: 将其抽象为一个函数; 使用宏;6.2.3. 不出现过长的函数。函数的长度原则上不超过100行,尤以不需要上下滚动屏幕即可查看全部函数内容为最佳(约为30-50行)6.2.4. 函数命名必须和该函数所执行的事务保持严格一致6.2.5. 变量名必须和该变量所承担的责任一致,不允许同一变量承担不同责任。6.2.6. 每个函数承担的职责尽量单一,不要设计功能过于集中的函数。例如:checkAndReportDetailData();该函数可以分解为:checkData();reportData();6.2.7. 检查接口函数(如类的公有方法、或者模块的接口函数)所有输入参数的有效性,并做相应的错误处理。6.2.8. 对于代码中因各种原因所采用临时的方案,必须标注:/* FIXME: */并附加必要的说明。6.2.9. 对于代码中因各种原因导致暂时不能实现的功能,必须标注:/* TODO: */并附加必要的说明。必要时可附加assert(flase)做强制提醒。6.2.10. 【推荐】原则上不修改open source的代码。对于所使用的Open Source的确不能满足需要或存在问题的,尽量采用其他方式来纠正,如Wrapper,以避免自己维护所带来的成本和错误。6.3. 效率原则程序执行时,应满足一定的空间和时间效率要求,在资源受限的编程环境下,代码的效率往往能左右产品的成败。6.3.1. 对于大对象的传递,使用引用传递(指针、引用)的方式而不是值传递以减少栈空间的开销。6.3.2. 程序中分配的内存、申请的文件句柄等资源,应在不用时及时释放或关闭,而不是程序结束时释放。6.3.3. 通过对系统数据结构的划分与组织的改进,以及对程序算法的优化来提高空间效率。6.3.4. 循环体内工作量最小化。 应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的时间效率6.3.5. 多重循环中,应将最忙的循环放在最内层。6.3.6. 避免循环体内含判断语句,将与循环变量无关的判断语句移到循环体外。 目的是减少判断次数。循环体中的判断语句是否可以移到循环体外,要视程序的具体情况而言,一般情况,与循环变量无关的判断语句可以移到循环体外,而有关的则不可以。6.3.7. 【推荐】尽量用乘法或其它方法代替除法,特别是浮点运算中的除法,在时间效率要求不是特别严格时,要优先保证程序的可读性。6.3.8. 对代码执行效率进行优化时,优先考虑优化程序结构,不应该为了追求局部效率而破坏代码的可读性。6.4. 可移植原则嵌入式环境下的代码,经常需要经过不同的编译器编译、在不同的CPU和不同的平台上运行。因此,代码必须具有一定的可移植性,以兼容不同环境带来的差异6.4.1. 不使用任何非标准C/C+语法和关键字6.4.2. 使用sizeof确定类、结构、变量的大小。同样一个类的声明,在不同的编译器上编译其大小可能是不同的。6.4.3. 不直接使用char, short, int, long等基本整数数据类型,而应对这些基本类型进行重定义后再使用。例如:typedef unsigned int UINT32;根据不同的平台调整UINT32的定义,可保证任何平台下该类型的变量都是一个32位的无符号整数,避免不同平台下整数位长带来的差异。6.4.4. 使用类、结构或其他数据类型时,不要依赖于其内存布局。不同的平台上同一个数据类型的内存布局可能是不一样。例如,下面的代码存在潜在的不可移植性:wchar_t title = L”ABC”;char* p = (char*) title;wchar_t capital = (*p+) 8 | (*p+);由于机器字高低位顺序的不同,上面这段代码在不同的平台上执行的结果完全不同。6.4.5. 当声明用于分布式环境或不同CPU间通信环境的数据结构时,必须考虑机器的字节顺序,使用的位域也要有充分的考虑。6.4.6. 代码中操作的资源属于和平台相关部分时,要根据该资源的特性进行接口抽象。代码中只能使用这些抽象后的、与平台无关的接口。移植时再根据平台对这些接口进行实现。6.5. 可测试原则代码必须是可测试的,只有经过测试的代码,才能在一定程度上保证执行的正确性。6.5.1. 模块编写应该有完善的测试方面的考虑。6.5.2. 建立可靠有效的日志系统,使用日志来调测软件尤其是多线程/进程软件的执行情况。6.5.3. 日志应该具有多种输出形式以满足不同的需求。一般应该保证可以输出到文件、屏幕或内存。6.5.4. 在同一项目组或产品组内,要有一套统一的为集成测试与系统联调准备的调测开关及相应的日志打印函数,并且要有详细的说明。6.5.5. 源代码中在必要的位置应该进行日志输出,如打印关键变量值、函数名称、函数值等。6.5.6. 在同一项目组或产品组内,日志打印出的信息串的格式要有统一的形式。6.5.7. 使用断言来发现软件问题,提高代码可测性。6.5.8. 用断言来检查程序正常运行时不应发生但在调测时有可能发生的非法情况6.5.9. 不能用断言代替错误处理来检查最终产品肯定会出现且必须处理的错误情况。6.5.10. 用断言保证没有定义实现的特性或功能不被使用。6.5.11. 可以在预计正常情况下程序不会到达的地方放置断言:assert false6.5.12. 断言可以用于检查传递给私有方法的参数。(对于公有方法,因为是提供给外部的接口,所以必须在方法中有相应的参数检验才能保证代码的健壮性)6.5.13. 正式软件产品中应把断言及其它调测代码去掉(即把有关的调测开关关掉)。6.5.14. 用调测开关来切换软件的DEBUG版和正式版,而不要同时存在正式版本和DEBUG版本的不同源文件,以减少维护的难度。6.5.15. 在软件系统中设置与取消有关测试手段,不能对软件实现的功能等产生影响。 即有测试代码的软件和关掉测试代码的软件,在功能行为上应一致。6.6. 编译原则6.6.1. 打开编译器的所有告警开关对程序进行编译,并保证编译过程中不出现警告信息。6.6.2. 对于确实无用的警告信息,可在编译器选项中关闭相应的开关。6.6.3. 在同一项目组或产品组中,要统一编译开关选项。6.6.4. 某些语句经编译后产生告警,但如果你认为它是正确的,那么应通过适当的手段去掉告警信息。例如,对于类型转换的警告,可进行强制类型转换;或使用编译器提供的去除警告的宏。6.7. 其他6.7.1. 【推荐】在平台允许的情况下,使用异常机制来进行错误通知和处理6.7.2. 【推荐】使用模板来进行代码复用7. 代码实现的流程代码实现分为四个阶段,即需求理解和详细设计、代码编写、代码检查和代码提交三个阶段。整个代码实现过程中,必须严格按照三阶段的流程执行,否则不允许进行提交。7.7.1. 需求理解和详细设计只有充分理解了需求,才可能编写出正确的代码。需求理解的过程可以有多种方式: 绘制UML图 与相关人员口头交流 接口检查(以代码检查的形式) 其他方式编写代码之前必须至少使用上述一种或多种方式来与模块的设计者和模块的使用者进行沟通,以保证实现和需求是一致的。7.2. 代码编写7.2.1. 编写一个模块时,应首先根据需求编写该模块的接口(即头文件中相关函数和方法以及对应的空实现),并将这部分代码送检,通过后提交,然后再进行真正的实现。7.2.2. 单元测试,开发人员应坚持对代码进行彻底的测试(单元测试),而不依靠他人或测试组来发现问题,每份代码必须包含对应的单元测试,无对应测试的代码应视为无效代码,不允许提交。7.2.3. 单元测试应和代码具有一定的比例,具体比例可根据实际情况设定。推荐至少达到1:1,即一行代码对应一行测试。7.2.4. 保证每个类(或C

温馨提示

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

评论

0/150

提交评论