1.介绍
编写规范的目的是为各开发团队提供编程规范的基础和参考,本文档并不是要成为终极编程规范,但是我们希望这些规范可以被广泛的接受。定义编程规范有助于提高开发速度,使得开发人员不需要总是从一些基本原则出发进行决策;有助于增进团队精神;有助于减少在一些小事上不必要的争论;使团队成员更容易阅读和维护其他成员的代码;有助于使开发人员放开手脚,在有意义的方向上发挥创造性。
在压力和时间的要求下,人们将按所受到的训练行事。他们会求助于习惯。作为软件开发人员,我们总是面对着巨大的压力,“要在昨天交付明天的软件”。在进度压力下,我们按所受到的训练和习惯工作。平时不知道培养软件工程良好实践的(或者不习惯应用这些实践的)马虎程序员,在压力下将编写出更加马虎、错误更多的代码。相反,养成良好习惯并经常按此工作的程序员将保持自己的组织性,快速提交高质量的代码的能力。
最后,规则并非一成不变的,欢迎加入来自实际应用中的经验和反馈。
2.文件结构
规则 2-1 一个文件中不要包含超过2000行的代码。
每个C程序通常分为两个文件。一个文件用于保存程序的声明(declaration),称为头文件。另一个文件用于保存程序的实现(implementation),称为定义(definition)。C 程序的头文件以“.h”为后缀,C 程序的定义文件以“. c”为后缀。一个文件中包含超过1000行的代码较难阅读,所以应该按照逻辑功能划分成多个文件。
此规则只适用于源代码
规则 2-2 文件为了防止头文件被重复引用,应当用#ifndef/#define/#endif 结构产生预处理块,建议宏定义为“_ 头文件的名字 _H”。
举例:头文件的名称为lun_pub.h,其预处理宏为_LUN_PUB_H。
3.注释
规则 3-1 说明性文件(如.h文件)头部必须包含统一风格的注释。注释中应该包含版权说明、文件名称、功能说明、版本号、作者、日期、修订说明等。
说明:对.h文件注释的示例:
/**
* COPYRIGHT NOTICE
* Copyright (c) 2010, MacroSAN
* All rights reserved.
*
* @file disk_pub.h
* 本文件主要定义磁盘子系统公用接口,包含下面几个部分的内容:\n
* 1. 磁盘子系统的对外接口;\n
* 2. 磁盘子系统与其他模块进行数据交互的数据结构;\n
* 3. 磁盘子系统相关的宏定义;\n
*
* 版本 作者 日期 修订说明
*
* 1.00 xxx 2010-08-10 最初版本
*/
规则 3-2 源文件头部必须包含统一风格的注释。注释中应该包含版权说明、文件名称、功能说明、版本号、作者、日期、修订说明等。
说明:对.c文件注释的示例:
/**
* COPYRIGHT NOTICE
* Copyright (c) 2010, MacroSAN
* All rights reserved.
*
* @file disk_mgt.c
* 本文件主要定义磁盘子系统磁盘管理的对外接口,包括查询磁盘信息、安全拔盘等;
*
* 版本 作者 日期 修订说明
*
* 1.00 xxx 2010-08-10 最初版本
*
*/
规则 3-3 函数头部必须包含统一风格的注释。注释中应该包含函数的功能、输入参数、输出参数、返回值,函数说明、作者、日期、修订说明、问题单号等。
说明:对函数注释的示例:
/** 通过磁盘的uuid查询磁盘的详细信息
*
* 该函数通过查询disk的配置文件来获取磁盘的详细信息,这些信息由struct disk_info_t定义
*
* @param[in]disk_uuid 磁盘的uuid
* @param[out]disk_info 指定磁盘的详细信息,输出参数
* @return 函数执行成功返回S_OK,否则返回相应的错误码
*
* @note disk_info为输出参数,在调用本函数时,需要先申请disk_info的内存;
*
* 作者 日期 问题单号 修订说明
*
* xxx 2010-08-10 未涉及 最初版本
*
* xxx 2010-11-29 xxx 增加debug打印;
*/
int32_t diskmgt_query_info(uuid_t * disk_uuid, disk_info_t *disk_info)
{
……
}
规则 3-4 对于宏、结构体和枚举代码的注释,需要简要说明其具体的含义,最好自注释的代码。
说明:对宏、结构体和枚举定义的示例:
#define PORT_NUM_PER_SP 2 /**< 每个控制器的最大channel */
#define DSU_NUM_PER_CHANNEL 16 /**< 每个channel上接的最大dsu数目 */
/** 描述dsu的位置的结构体
*
* DSU的名称格式为:DSU-DSU ID,DSU ID的编号规则是Port ID:DSU Location ID,
* 即端口ID:DSU位置编号,DSU位置编号表示DSU级数,从1开始编号
*/
typedef struct dsu_location
{
uint32_t port_id; /**< spu的port id*/
uint32_t dsu_id; /**< dsu的location id*/
}dsu_location_t;
规则 3-5 源代码应该使用/…/ 类型的注释,并且/…./字符序列中不能再包含/*。
C不支持注释的嵌套,尽管一些编译器支持它以做为语言扩展。一段注释以/开头,直到第一个/为止,在这当中出现的任何/*都违反了本规则。示例如下:
/* some comment, end comment marker accidentally omitted
<<New Page>>
Perform_Critical_Safety_Function (X);
/* this comment is not compliant */
在检查包含函数调用的页中,假设它是可执行代码。
建议 3-1 注释应考虑程序易读及外观排版的因素,使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达。
注释语言不统一,影响程序易读性和外观排版,出于对维护人员的考虑,建议使用中文。
4.程序版式
规则 4-1 程序块要采用缩进风格编写,缩进的空格数为4个。
说明:对于由开发工具自动生成的代码可以有不一致。
规则 4-2 在每个函数定义结束之后都要加空行。
示例:
// 空行
void Function1(.)
{
...
}
// 空行
void Function2(.)
{
...
}
// 空行
规则 4-3 在一个函数体内,逻辑上密切相关的语句之间不加空行,其它地方应加空行分隔。
示例:
// 空行
while (condition)
{
statement1;
// 空行
if (condition)
{
statement2;
}
else
{
statement3;
}
// 空行
statement4;
}
规则 4-4 一行代码只做一件事情,如只定义一个变量,或只写一条语句。
规则 4-5 if、for、while、do等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加{}。
规则 4-6 程序块的分界符{}应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用缩进方式。
不符合规范的示例:
f
or (...) {
... // program code
}
if (...)
{
... // program code
}
符合规范的示例:
for (...)
{
... // program code
}
if (...)
{
... // program code
}
规则 4-7 一行程序以小于80字符为宜,不要写得过长。
规则 4-8 长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。
示例:
if ((very_longer_variable1 >= very_longer_variable12)
&& (very_longer_variable3 <= very_longer_variable14)
&& (very_longer_variable5 <= very_longer_variable16))
{
dosomething();
}
规则 4-9 尽可能在定义变量的同时初始化该变量(就近原则)。