logo资料库

软件开发代码规范.docx

第1页 / 共56页
第2页 / 共56页
第3页 / 共56页
第4页 / 共56页
第5页 / 共56页
第6页 / 共56页
第7页 / 共56页
第8页 / 共56页
资料共56页,剩余部分请下载后查看
1规范制订说明
1.1前言
1.2代码总体原则
1.3术语定义
2头文件
2.1背景
2.2术语定义
3函数
4标识符命名与定义
4.1通用命名规则
4.2文件命名规则
4.3变量命名规则
4.4函数命名规则
4.5宏的命名规则
5变量
6宏、常量
7质量保证
8程序效率
9注释
10排版与格式
11表达式
12代码编辑、编译
13可测性
14安全性
14.1字符串操作安全
14.2整数安全
14.3格式化输出安全
14.4文件I/O安全
14.5其它
15单元测试
16可移植性
17版本说明
18业界编程规范
软件开发代码规范
历史记录 版本号 V1.0.0 日期 制/修订人 内容描述
目录 1 规范制订说明 .......................................................................................................................................................... 1 1.1 前言 ............................................................................................................................................................... 1 1.2 代码总体原则 ...............................................................................................................................................1 1.3 术语定义 ....................................................................................................................................................... 1 2 头文件...................................................................................................................................................................... 2 2.1 背景 ............................................................................................................................................................... 2 2.2 术语定义 ....................................................................................................................................................... 2 3 函数 .......................................................................................................................................................................... 7 4 标识符命名与定义 ................................................................................................................................................16 4.1 通用命名规则 .............................................................................................................................................16 4.2 文件命名规则 .............................................................................................................................................18 4.3 变量命名规则 .............................................................................................................................................18 4.4 函数命名规则 .............................................................................................................................................19 4.5 宏的命名规则 .............................................................................................................................................19 5 变量 ........................................................................................................................................................................ 20 6 宏、常量 ................................................................................................................................................................ 23 7 质量保证 ................................................................................................................................................................ 26 8 程序效率 ................................................................................................................................................................ 30 9 注释 ........................................................................................................................................................................ 32 10 排版与格式.......................................................................................................................................................... 37 11 表达式.................................................................................................................................................................. 39 12 代码编辑、编译..................................................................................................................................................42 13 可测性.................................................................................................................................................................. 42 14 安全性.................................................................................................................................................................. 43 14.1 字符串操作安全.......................................................................................................................................44 14.2 整数安全 ...................................................................................................................................................45 14.3 格式化输出安全.......................................................................................................................................48 14.4 文件 I/O 安全............................................................................................................................................50 14.5 其它 ........................................................................................................................................................... 51 15 单元测试 .............................................................................................................................................................. 52 16 可移植性 .............................................................................................................................................................. 52 17 版本说明 .............................................................................................................................................................. 53 18 业界编程规范 ......................................................................................................................................................53
第 1页/共 53页 1 规范制订说明 1.1 前言 为了提高产品代码质量,指导软件开发人员编写出简洁、可维护、可靠、可测试、高效、可移植的代码, 编写了本规范。在本规范的最后,列出了一些业界比较优秀的编程规范,作为延伸阅读参考材料。 1.2 代码总体原则 1、清晰第一 清晰性是易于维护、易于重构的程序必需具备的特征。代码首先是给人读的,好的代码应当可以像文章一 样发声朗诵出来。 目前软件维护期成本占整个生命周期成本的 40%~90%。根据业界经验,维护期变更代码的成本,小型系 统是开发期的 5 倍,大型系统(100 万行代码以上)可以达到 100 倍。业界的调查指出,开发组平均大约 一半的人力用于弥补过去的错误,而不是添加新的功能来帮助公司提高竞争力。 “程序必须为阅读它的人而编写,只是顺便用于机器执行。”——Harold Abelson 和 Gerald Jay Sussman “编写程序应该以人为本,计算机第二。”——Steve McConnell 本规范通过后文中的原则(如头优秀的代码可以自我解释,不通过注释即可轻易读懂/头文件中适合放置接 口的声明,不适合放置实现/除了常见的通用缩写以外,不使用单词缩写,不得使用汉语拼音)、规则(如 防止局部变量与全局变量同名)等说明清晰的重要性。 一般情况下,代码的可阅读性高于性能,只有确定性能是瓶颈时,才应该主动优化。 2、简洁为美 简洁就是易于理解并且易于实现。代码越长越难以看懂,也就越容易在修改时引入错误。写的代码越多, 意味着出错的地方越多,也就意味着代码的可靠性越低。因此,我们提倡大家通过编写简洁明了的代码来 提升代码可靠性。 废弃的代码(没有被调用的函数和全局变量)要及时清除,重复代码应该尽可能提炼成函数。 本规范通过后文中的原则(如文件应当职责单一/一个函数仅完成一件功能)、规则(重复代码应该尽可能 提炼成函数/避免函数过长,新增函数不超过 50 行)等说明简洁的重要性。 3、选择合适的风格,与代码原有风格保持一致 产品所有人共同分享同一种风格所带来的好处,远远超出为了统一而付出的代价。在公司已有编码规范的 指导下,审慎地编排代码以使代码尽可能清晰,是一项非常重要的技能。如果重构/修改其他风格的代码时, 比较明智的做法是根据现有代码的现有风格继续编写代码,或者使用格式转换工具进行转换成公司内部风 格。 1.3 术语定义 原则:编程时必须坚持的指导思想。 规则:编程时强制必须遵守的约定。 建议:编程时必须加以考虑的约定。 说明:对此原则/规则/建议进行必要的解释。 示例:对此原则/规则/建议从正、反两个方面给出例子。 延伸阅读材料:建议进一步阅读的参考材料。
第 2页/共 53页 2 头文件 2.1 背景 对于 C 语言来说,头文件的设计体现了大部分的系统设计。不合理的头文件布局是编译时间过长的根因, 不合理的头文件实际上不合理的设计。 2.2 术语定义 依赖:本章节特指编译依赖。若 x.h 包含了 y.h,则称作 x 依赖 y。依赖关系会进行传导,如 x.h 包含 y.h, 而 y.h 又包含了 z.h,则 x 通过 y 依赖了 z。依赖将导致编译时间的上升。虽然依赖是不可避免的,也是必 须的,但是不良的设计会导致整个系统的依赖关系无比复杂,使得任意一个文件的修改都要重新编译整个 系统,导致编译时间巨幅上升。 在一个设计良好的系统中,修改一个文件,只需要重新编译数个,甚至是一个文件。 某产品曾经做过一个实验,把所有函数的实现通过工具注释掉,其编译时间只减少了不到 10%,究其原因, 在于 A 包含 B,B 包含 C,C 包含 D,最终几乎每一个源文件都包含了项目组所有的头文件,从而导致绝 大部分编译时间都花在解析头文件上。 某产品更有一个“优秀实践”,用于将.c 文件通过工具合并成一个比较大的.c 文件,从而大幅度提高编译 效率。其根本原因还是在于通过合并.c 文件减少了头文件解析次数。但是,这样的“优秀实践” 是对合 理划分.c 文件的一种破坏。 《google C++ Style Guide》1.2 头文件依赖 章节也给出了类似的阐述: 若包含了头文件 aa.h,则就引入了新的依赖:一旦 aa.h 被修改,任何直接和间接包含 aa.h 代码都会被重新 编译。如果 aa.h 又包含了其他头文件如 bb.h,那么 bb.h 的任何改变都将导致所有包含了 aa.h 的代码被重 新编译,在敏捷开发方式下,代码会被频繁构建,漫长的编译时间将极大的阻碍频繁构建。因此,我们倾 向于减少包含头文件,尤其是在头文件中包含头文件,以控制改动代码后的编译时间。 合理的头文件划分体现了系统设计的思想,但是从编程规范的角度看,仍然有一些通用的方法,用来合理 规划头文件。本章节介绍的一些方法,对于合理规划头文件会有一定的帮助。 原则 1.1 头文件中适合放置接口的声明,不适合放置实现。 说明:头文件是模块(Module)或单元(Unit)的对外接口。头文件中应放置对外部的声明,如对外提供 的函数声明、宏定义、类型定义等。 内部使用的函数(相当于类的私有方法)声明不应放在头文件中。内部使用的宏、枚举、结构定义不应放 入头文件中。 变量定义不应放在头文件中,应放在.c 文件中。 变量的声明尽量不要放在头文件中,亦即尽量不要使用全局变量作为接口。变量是模块或单元的内部实现 细节,不应通过在头文件中声明的方式直接暴露给外部,应通过函数接口的方式进行对外暴露。即使必须 使用全局变量,也只应当在.c 中定义全局变量,在.h 中仅声明变量为全局的。 延伸阅读材料:《C 语言接口与实现》(David R. Hanson 著 傅蓉 周鹏 张昆琪 权威 译 机械工业出版社 2004 年 1 月)(英文版: "C Interfaces and Implementations") 原则 1.2 头文件应当职责单一。 说明:头文件过于复杂,依赖过于复杂是导致编译时间过长的主要原因。很多现有代码中头文件过大, 职 责过多,再加上循环依赖的问题,可能导致为了在.c 中使用一个宏,而包含十几个头文件。
第 3页/共 53页 示例:如下是某平台定义 WORD 类型的头文件: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include … typedef unsigned short WORD; … 这个头文件不但定义了基本数据类型 WORD,还包含了 stdio.h syslib.h 等等不常用的头文件。如果工程中 有 10000 个源文件,而其中 100 个源文件使用了 stdio.h 的 printf,由于上述头文件的职责过于庞大,而 WORD 又是每一个文件必须包含的,从而导致 stdio.h/syslib.h 等可能被不必要的展开了 9900 次,大大增加了工程 的编译时间。 原则 1.3 头文件应向稳定的方向包含。 说明:头文件的包含关系是一种依赖,一般来说,应当让不稳定的模块依赖稳定的模块,从而当不稳定的 模块发生变化时,不会影响(编译)稳定的模块。 就我们的产品来说,依赖的方向应该是:产品依赖于平台,平台依赖于标准库。某产品线平台的代码中已 经包含了产品的头文件,导致平台无法单独编译、发布和测试,是一个非常糟糕的反例。 除了不稳定的模块依赖于稳定的模块外,更好的方式是两个模块共同依赖于接口,这样任何一个模块的内 部实现更改都不需要重新编译另外一个模块。在这里,我们假设接口本身是最稳定的。 延伸阅读材料:编者推荐开发人员使用“依赖倒置”原则,即由使用者制定接口,服务提供者实现接口, 更具体的描述可以参见《敏捷软件开发:原则、模式与实践》(Robert C.Martin 著 邓辉 译 清华大学出 版社 2003 年 9 月) 的第二部分“敏捷设计”章节。 规则 1.1 每一个.c 文件应有一个同名.h 文件,用于声明需要对外公开的接口。 说明:如果一个.c 文件不需要对外公布任何接口,则其就不应当存在,除非它是程序的入口,如 main 函 数所在的文件。 现有某些产品中,习惯一个.c 文件对应两个头文件,一个用于存放对外公开的接口,一个用于存放内部需 要用到的定义、声明等,以控制.c 文件的代码行数。编者不提倡这种风格。这种风格的根源在于源文件过
第 4页/共 53页 大,应首先考虑拆分.c 文件,使之不至于太大。另外,一旦把私有定义、声明放到独立的头文件中,就无 法从技术上避免别人 include 之,难以保证这些定义最后真的只是私有的。 本规则反过来并不一定成立。有些特别简单的头文件,如命令 ID 定义头文件,不需要有对应的.c 存在。 示例:对于如下场景,如在一个.c 中存在函数调用关系: void foo() { bar(); } void bar() { Do something; } 必须在 foo 之前声明 bar,否则会导致编译错误。 这一类的函数声明,应当在.c 的头部声明,并声明为 static 的,如下: static void bar(); void foo() { bar(); } void bar() { Do something; } 规则 1.2 禁止头文件循环依赖。 说明:头文件循环依赖,指 a.h 包含 b.h,b.h 包含 c.h,c.h 包含 a.h 之类导致任何一个头文件修改,都导致 所有包含了 a.h/b.h/c.h 的代码全部重新编译一遍。而如果是单向依赖,如 a.h 包含 b.h,b.h 包含 c.h,而 c.h 不包含任何头文件,则修改 a.h 不会导致包含了 b.h/c.h 的源代码重新编译。 规则 1.3 .c/.h 文件禁止包含用不到的头文件。 说明:很多系统中头文件包含关系复杂,开发人员为了省事起见,可能不会去一一钻研,直接包含一切想 到的头文件,甚至有些产品干脆发布了一个 god.h,其中包含了所有头文件,然后发布给各个项目组使用, 这种只图一时省事的做法,导致整个系统的编译时间进一步恶化,并对后来人的维护造成了巨大的麻烦。 规则 1.4 头文件应当自包含。 说明:简单的说,自包含就是任意一个头文件均可独立编译。如果一个文件包含某个头文件,还要包含另 外一个头文件才能工作的话,就会增加交流障碍,给这个头文件的用户增添不必要的负担。 示例: 如果 a.h 不是自包含的,需要包含 b.h 才能编译,会带来的危害:
第 5页/共 53页 每个使用 a.h 头文件的.c 文件,为了让引入的 a.h 的内容编译通过,都要包含额外的头文件 b.h。额外的头 文件 b.h 必须在 a.h 之前进行包含,这在包含顺序上产生了依赖。 注意:该规则需要与“.c/.h 文件禁止包含用不到的头文件”规则一起使用,不能为了让 a.h 自包含,而在 a.h 中包含不必要的头文件。a.h 要刚刚可以自包含,不能在 a.h 中多包含任何满足自包含之外的其他头文 件。 规则 1.5 总是编写内部#include 保护符(#define 保护)。 说明:多次包含一个头文件可以通过认真的设计来避免。如果不能做到这一点,就需要采取阻止头文件内 容被包含多于一次的机制。 通常的手段是为每个文件配置一个宏,当头文件第一次被包含时就定义这个宏,并在头文件被再次包含时 使用它以排除文件内容。 所有头文件都应当使用#define 防止头文件被多重包含,命名格式为 FILENAME_H,为了保证唯一性,更 好的命名是 PROJECTNAME_PATH_FILENAME_H。 注:没有在宏最前面加上“_”,即使用 FILENAME_H 代替_FILENAME_H_,是因为一般以“_”开头的 标识符为系统保留或者标准库使用,在有些静态检查工具中,若全局可见的标识符以“_”开头会给出告 警。 定义包含保护符时,应该遵守如下规则: 1)保护符使用唯一名称; 2)不要在受保护部分的前后放置代码或者注释。 示例:假定 VOS 工程的 timer 模块的 timer.h,其目录为 VOS/include/timer/timer.h,应按如下方式保护: #ifndef VOS_INCLUDE_TIMER_TIMER_H #define VOS_INCLUDE_TIMER_TIMER_H ... #endif 也可以使用如下简单方式保护: #ifndef TIMER_H #define TIMER_H .. #endif 例外情况:头文件的版权声明部分以及头文件的整体注释部分(如阐述此头文件的开发背景、使用注意事 项等)可以放在保护符(#ifndef XX_H)前面。 规则 1.6 禁止在头文件中定义变量。 说明:在头文件中定义变量,将会由于头文件被其他.c 文件包含而导致变量重复定义。 规则 1.7 只能通过包含头文件的方式使用其他.c 提供的接口,禁止在.c 中通过 extern 的方式使用外部函数 接口、变量。 说明:若 a.c 使用了 b.c 定义的 foo()函数,则应当在 b.h 中声明 extern int foo(int input);并在 a.c 中通过#include 来使用 foo。禁止通过在 a.c 中直接写 extern int foo(int input);来使用 foo,后面这种写法容易在 foo 改 变时可能导致声明和定义不一致。 规则 1.8 禁止在 extern "C"中包含头文件。
分享到:
收藏