C++编码规范
2020-11-23 20:49
标签:des style blog class width strong get string int 文件 html 在阅读之前同事写的源代码,发现格式非常混乱,不方便阅读和维护,所以打算这词代码编写之前,先定好编写规范,下面这篇文章是我看到比较全面比较详细的编码规范,感觉很不错,所以转过来了,再次,感谢原作者的分享。 转自:http://www.cnitblog.com/qiuyangzh/archive/2005/07/15/973.html 本编码规范针对C++语言。制定本规范的目的: 提高代码的健壮性,使代码更安全、可靠; 提高代码的可读性,使代码易于查看和维护。 本文档分别对C++程序的格式、注释、标识符命名、语句使用、函数、类、程序组织、公共变量等方面做出了要求。规范分为两个级别——规则和建议。规则级的规范要求开发人员必须要遵守,建议级的规范开发人员应尽量遵守。 各项目组在用C++语言或基于C++语言的开发工具开发项目时,要遵守本规范。 以下是各条规范的具体内容。 对代码书写格式的要求。 规范级别:规则 规则描述: ●在头文件和实现文件中,各主要部分之间要用空行隔开。 所谓文件的主要部分,包括:序言性注释、防止被重复包含部分(只在头文件中)、#
include部分、#define部分、类型声明和定义部分、实现部分等等。 ●在一个函数中,完成不同功能的部分,要用空行隔开。 理由: 段落分明,提高代码的可读性。 规范级别:规则 规则描述: ●在使用赋值运算符、逻辑运算符、位运算符、算术运算符等二元操作符时,在其两边各加一个空格。 例: nCount = 2;而不是 nCount=2; ● 函数的各参数间要用“,”和一个空格隔开。
例:void GetDate(int x, int y); 而不是void GetDate(int x,int y)或void GetDate(int x ,int y)。 理由: 提高代码的可读性。 规范级别:规则 规则描述: ●不要在引用操作符前后使用空格,引用操作符指“.”和“->”,以及“[]”。 ●不要在“::”前后使用空格。 ●不要在一元操作符和其操作对象之间使用空格,一元操作符包括“++”、“--”“!”、“&”“*”等。 理由: 提高代码的可读性。 举例: // 不要象下面这样写代码: //应该写成这样 m_pFont->CreateFont(); 规范级别:规则 规则描述: 对程序语句要按其逻辑进行水平缩进,以两个空格为单位,使同一逻辑层次上的代码在列上对齐。 理由: 提高代码的可读性。 规范级别:规则 规则描述: 较长的语句要分成多行书写。长表达式要在低优先级操作符处分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,缩进长度以两个空格或Tab符长度为单位。 理由: 提高代码的可读性。 举例: // 下面是一个处理的较为合理的例子 nCount = Fun1(n1, n2, n3) + (nNumber1 * GetDate(n4, n5, n6)) * nNumber1; 规范级别:规则 规则描述: 控制语句(if , for , while , do...whule)的语句部分一定要用 ‘{ ’和‘
}’括起来(即使只有一条语句),并且‘{ ’和‘ }’应处在同一列上。 理由: 这样做,能够划分出清晰的语句块,使语句的归属明确,使代码更加容易阅读和修改。 举例: //不要象下面这样写代码: if (x == 0) return; else while (x > min) x--; // 应该这样写 if (x == 0) { return; } else { while (x > min) { x--; } } 规范级别:规则 规则描述: 一行只写一条程序语句。 理由: 提高代码的可读性。 举例: // 不要这样写 x = x0; y = y0; while(IsOk(x)) {x++;} // 应该这样写代码 x = x0; y = y0; while(IsOk(x)) { x++; } 规范级别:规则 规则描述: 一次(一条声明、定义语句)只声明、定义一个变量。 理由: 提高代码的可读性。 举例: // 应该这样写 int width; int length; // 不要这样写 int width, length; 规范级别:建议 规则描述: 对于一个表达式,在一个二元、三元操作符操作的操作数的两边,应该放置“(”和“)”。 理由: 避免出现不明确的运算、赋值顺序,提高代码的可读性。 举例: // 下面这行代码: result = fact / 100 * number + rem; //最好写成这样 规范级别:规则 规则描述: 在定义指针、引用变量时,将操作符“*”、“&”和类型写在一起。 理由: 统一格式,提高代码的可读性。 举例: // 不要象下面这样写代码: //而应该写成这样 char* s; 这一部分对程序注释提出了要求。 程序中的注释是程序与日后的程序读者之间通信的重要手段。良好的注释能够帮助读者理解程序,为后续阶段进行测试和维护提供明确的指导。 下面是关于注释的基本原则: 1. 注释内容要清晰明了,含义准确,防止出现二义性。 2. 边写代码边注释,修改代码的同时修改相应的注释,保证代码与注释的一致性。 规范级别:规则 规则描述: ●在函数的声明之前,要给出精练的注释(不必牵扯太多的内部细节),让使用者能够快速获得足够的信息使用函数。格式不做具体要求。 ●在函数的定义之前,要给出足够的注释。注释格式要求如下: /************************************************************************* 【函数名称】 (必需) 【函数功能】 (必需) 【参数】
(必需。标明各参数是输入参数还是输出参数。) 【访问变量】 (必需。列出该函数访问的全局变量、成员变量。) 【返回值】 (必需。解释返回值的意义。) 【使用情况】 (必需。调用其它函数的情况,被调用的情况) 【开发者及日期】 (必需) 【版本】 (必需) 【更改记录】 (若有修改,则必需注明) *************************************************************************/ 理由: 提高代码的可读性。 规范级别:规则 规则描述: ● 在类的声明之前,要给出足够而精练的注释。注释格式要求如下: /************************************************************************* 【类名】
(必需) 【功能】 (必需) 【接口说明】 (必需) 【开发者及日期】 (必需) 【版本】
(必需) 【版权信息】 (可选) 【更改记录】 (若修改过则必需注明) *************************************************************************/ 理由: 提高代码的可读性。 规范级别:规则 规则描述: 在头文件、实现文件的首部,一定要有文件注释,用来介绍文件内容。注释格式要求如下: /************************************************************************* 【文件名】
(必需) 【功能模块和目的】 (必需) 【开发者及日期】 (必需) 【版本】
(必需) 【版权信息】
(必需) 【更改记录】
(若修改过则必需注明) *************************************************************************/ 理由: 提高代码的可读性。 规范级别:建议 规则描述:
建议对每个空循环体给出确认性注释。 理由:
提示自己和别人,这是空循环体,并不是忘了。 举例: while(g_bOpen == FALSE) {
//空循环 } 规范级别:建议 规则描述: 建议对多个case语句共用一个出口的情况给出确认性注释。 理由:
提示自己和别人,这几个case语句确实是共用一个出口,并不是遗漏了。 举例: switch(nNumber)
{
case 1: nCount++; break;
case 2:
case 3: nCount--; break; //
当nNumber等于2或3时,进行同样的处理 default: break; } 规范级别:建议 规则描述: 除上面说到的,对于以下情况,也应该考虑进行注释: l 变量的声明、定义。通过注释,解释变量的意义、存取关系等; 例如: int
m_nNumber; //记录图形个数。被SetDate( )、GetDate( )使用。 l 数据结构的声明。通过注释,解释数据结构的意义、用途等; 例如:
//定义结构体,存储元件的端点。用于将新旧的端点对应。 typedef struct {
int nBNN;
int nENN;
int nBNO;
int nENO; }Element; l分支。通过注释,解释不同分支的意义; 例如:
if(m_iShortRadio == 0)
//三相的情况
{
strvC.Format("%-10.6f", vC);
straC.Format("%-10.6f", aC);
}
else if(m_iShortRadio ==
1) //两相的情况
{
strvC =
_T("");
straC =
_T("");
} l调用函数。通过注释,解释调用该函数所要完成的功能; 例如:
SetDate(m_nNumber
); //设置当前的图形个数。 l 赋值。通过注释,说明赋值的意义; 例如: m_bDraw =
true; //将当前设置为绘图状态 l 程序块的结束处。通过注释,标识程序块的结束。
例如:
if (name = = White)
{
… if (age = = 20) { …
}//年龄判断、处理结束 …
}//姓名判断、处理结束 l其它有必要加以注释的地方; 理由: 提高代码的可读性。 规范级别:建议 规则描述: 同一个函数或模块中的行末注释应尽量对齐。 理由: 提高代码的可读性。 举例: nCount =
0;
//计数器,表示正在处理第几个数据块 BOOL bNeedSave;
//是否保存从服务器返回的数据 BOOL bReturnCache;
//是否将Cache中的内容返回客户端 DWORD BytesWritten; //写入的数据长度 规范级别:规则 规则描述: 注释行的数量不得少于程序行数量的1/3。 对标识符和文件的命名要求。 规范级别:规则 规则描述: 在程序中声明、定义的变量、常量、宏、类型、函数,在对其命名时应该遵守统一的命名规范。具体要求如下:
一般变量名应以小写字母打头,各英文描述单词的首字母分别大写,其他字母一律小写。对于不同作用域的变量,其命名要求如下表所示: 表2-1 变量命名 变量种类 前缀要求 示例 全局变量 g_ g_Number 全局指针变量 g_p g_pNumber 对象级变量(类内数据成员) 文件作用域变量(文件中静态变量) m_ m_Number 对象级指针变量(类内指针数据成员) 文件作用域指针变量(文件中静态指针变量) m_p m_pNumber 函数级变量(局部变量) 无要求 number 函数级指针变量(局部指针变量) p pNumber
上表列出了对变量命名的基本要求。项目组或程序员可在该要求上再进行细化,但必须保证符合该要求。
常量的名字要全部大写。常量指: const修饰的量。如const int NUMBER = 100; 枚举量。如enum{ ONE,TWO,THREE };
所有用宏形式定义的名字,包括宏常量和宏函数,名字要全部大写。
自定义类型名应以大写字母打头。C++中自定义类型包括:class、struct、enum、union、typedef声明的类型、namespace。 例如:typedef struct Student; class CMsgDialog;
函数名应以大写字母打头。 例如:void GetCount(); 下面还有一些在命名时应该遵守的基本规范:
例如:m_LastCount 中要大写L和C;
例如:_bFind 是不允许出现的变量;
例如:m_bFind 和 M_BFIND;
例如:m_strError 表示错误的字符串; 理由: 减少命名冲突;提高代码的可读性。 规范级别:规则 规则描述: 在程序中声明、定义的变量、常量、宏、类型、函数,它们的名字长度要在4至25个字符之内(下限不包括前缀,上限包括名字中所有的字符)。 对于某些已经被普遍认同的简单命名,可不受本规则的限制。如for循环的循环记数变量,可使用 i 、j 等简单字符命名。 理由: 名字长度应该在一个恰当的范围内,名字太长不够简洁,名字太短又不能清晰表达含义。 规范级别:建议 规则描述: 代码文件的名字要与文件中声明、定义的类的名字基本保持一致,使类名与类文件名建立联系。 理由: 使应用程序容易理解。 举例: 将类CMsgDialog的头文件和实现文件命名为msgdialog.h和msgdialog.cpp就是一种比较简单、恰当的方法。 对具体程序语句的使用要求。 规范级别:建议 规则描述: 在一条程序语句中,只应包含一个赋值操作符。赋值操作符包括:=, +=, -=, *=, /=, %=, >>=,
理由: 避免产生不明确的赋值顺序。 举例: // 不要这样写 b = c = 5; a = (b * c) + d++; // 应该这样写 c = 5; b = c; a = (b * c) + d; d++; 规范级别:建议 规则描述: 不要在控制语句if, while, for 和 switch的条件表达式中使用赋值操作符。赋值操作符包括:=, +=, -=,
*=, /=, %=, >>=,
理由: 一个类似于 if (x = y)这样的写法是不明确、不清晰的,代码的作者也许是想写成这样: if (x == y)。 举例: //不要象下面这样写代码: if (x -= dx) { ... } //应该这样写: x -= dx; if (x) { ... } 规范级别:建议 规则描述: 在一个赋值表达式中: ? 一个左值,在表达式中应该仅被赋值一次。 ? 对于多重赋值表达式,一个左值在表达式中仅应出现一次,不要重复出现。 理由: 避免产生不明确的赋值顺序。 举例: //不要象下面这样写代码: i = t[i++]; //一个左值,在表达式中应该仅被赋值一次 a = b = c + a;
//对于多重赋值表达式,一个左值在表达式中仅应出现一次,不能重复出 现。 i = t[i] = 15;
//对于多重赋值表达式,一个左值在表达式中仅应出现一次,不能重复出现。 规范级别:建议 规则描述: 对于if, while, for等控制语句的条件表达式,建议使用正规的布尔格式。 理由: 使代码更容易理解。 举例: //不要象下面这样写代码: while(1) { ... } if(test) { ... } for(i = 1; function_call(i); i++) { ... } //最好这样写: AlwaysTrue = true; while(AlwaysTrue == true) { ... } if(test == true) { ... } for(i = 1; function_call(i) == true; i++) { ... } 规范级别:规则 规则描述: 程序中不要使用goto语句。 理由: 这条规则的目的是为了确保程序的结构化,因为滥用goto语句会使程序流程无规则,可读性差。 Goto语句只在一种情况下有使用价值,就是当要从多重循环深处跳转到循环之外时,效率很高,但对于一般要求的软件,没有必要费劲心思追求多么高的效率,而且效率主要是取决于算法,而不在于个别的语句技巧。 规范级别:规则 规则描述: 在控制语句 (for, do, while) 块中,禁止使用Break和continue。 在switch中的case语句块不受该规则限制。 理由: 在控制语句 (for, do, while)
块中使用Break和continue,会打乱代码结构化的流程,使代码的可读性降低。 规范级别:规则 规则描述: 字符串的赋值应采用_T(“”)模式。 理由: 改善可移植性。 举例: //不要象下面这样写代码: Cstring strError =
“syntax error”; //应该这样写: Cstring strError = _T(“syntax error”); 规范级别:规则 规则描述: 不要对浮点类型的数据做等于、不等于这些精确的比较判断,要用范围比较代替精确比较。 理由: 由于存在舍入的问题,计算机内部不能精确的表示所有的十进制浮点数,用等于、不等于这种精确的比较方法就可能得出与预期相反的结果。所以应该用大于、小于等范围比较的方法代替精确比较的方法。 举例: //不要象下面这样写代码: float number; … … if (number = =
0)
//精确比较 … … 规范级别:规则 规则描述: 局部的new 和 delete 要成对出现; new要与delete对应,new[]要与delete[]对应。 理由: 防止内存泄露。 规范级别:规则 规则描述: switch语句中的每一个case分支,都要以break作为分支的结尾(几个连续的空case语句允许共用一个)。 理由: 使代码更容易理解;减少代码发生错误的可能性。 规范级别:规则 规则描述: 在switch语句块中,一定要有default分支来处理其它情况。 理由: 用来处理switch语句中默认、特殊的情况。 规范级别:建议 规则描述: 在定义指针变量的同时,对其进行初始化。如果定义时还不能为指针变量赋予有效值,则使其指向NULL。 理由: 减少使用未初始化指针变量的几率。 举例: // 不要这样写代码 int* y ; y = &x ; ... // 应该这样写 int* y = &x; ... 规范级别:建议 规则描述: 当指针变量所指的内存被释放后,应该赋予指针一个合理的值。除非该指针变量本身将要消失这种情况下不必赋值,否则应赋予NULL。 理由: 保证指针变量在其生命周期的全过程都指向一个合理的值。 规范级别:规则 规则描述: 在代码中用ptr->fld的形式代替(*ptr).fld的形式。 对函数的要求。 规范级别:规则 规则描述: 函数体代码长度不得超过100行(不包括注释)。 理由: 明确函数功能(一个函数仅完成一件事情),精确(而不是近似)地实现函数设计。 规范级别:建议 规则描述: 将重复使用的简单操作编写成函数。 理由: 对于重复使用的功能,虽然很简单,也应以函数的形式来处理,这样可以简化代码,使代码更易于维护。 规范级别:规则 规则描述: 应该尽量保证一个函数只有一个出口。 理由: 增加函数的可靠性。 规范级别:规则 规则描述: 在声明和定义函数时,在函数参数列表中为各参数指定类型和名称。 理由: 提高代码的可读性,改善可移植性。 举例: // 不要象下面这样写代码: f(int, char*); //函数声明 f(a,
b)
//函数定义 int a; char* b { ... } // 应该这样写: f(int a, char* b); f(int a, char* b) { ... } 规范级别:规则 规则描述: 要为每一个函数指定它的返回值。如果函数没有返回值,则要定义返回类型为void。 理由: 提高代码的可读性;改善代码的可移植性。 规范级别:建议 规则描述: 函数调用语句中,在函数的参数列表中不要使用赋值操作符。赋值操作符包括=, +=, -=, *=, /=, %=,
>>=,
理由: 避免产生不明确的赋值顺序。 举例: // 不要象下面这样写代码: void fun1(int a); void fun2(int b) { fun1(++b);
//注意这里! } 规范级别:规则 规则描述: 编写可重入函数时,若操作全局变量,则应加以保护。 举例: 如果全局变量不加以保护,当多个线程调用此函数时,很可能使此变量变为不可知状态。 例如:假设
Exam是int型全局变量,函数Squre_Exam返回Exam平方值,如下函数不具有可重入性。
Unsigned int example (int para)
{
unsigned int temp;1 前言
2 编码规范正文
2.1格式
2.1.1 空行的使用
2.1.2 哪里应该使用空格
2.1.3 哪里不应该使用空格
m_pFont -> CreateFont();
2.1.4 缩进
2.1.5 长语句的书写格式
2.1.6 清晰划分控制语句的语句块
2.1.7 一行只写一条语句
2.1.8 一次只声明、定义一个变量
2.1.9 在表达式中使用括号
result = ((fact / 100) * number) + rem;
2.1.10将操作符“*”、“&”和类型写在一起
char *s;
2.2注释
2.2.1 对函数进行注释
2.2.2 对类进行注释
2.2.3 对文件进行注释
2.2.4 对每个空循环体要给出确认性注释
2.2.5 对多个case语句共用一个出口的情况给出确认性注释
2.2.6 其它应该考虑进行注释的地方
2.2.7 行末注释尽量对齐
2.2.8 注释量
2.3命名
2.3.1 标识符命名要求
2.3.2 标识符长度要求
2.3.3 文件命名要求
2.4语句
2.4.1 一条程序语句中只包含一个赋值操作符
2.4.2 不要在控制语句的条件表达式中使用赋值操作符
2.4.3 赋值表达式中的规定
2.4.4 使用正规格式的布尔表达式
2.4.5 禁用Goto语句
2.4.6 程序中禁用break、continue
2.4.7 字符串的赋值
2.4.8 避免对浮点数值类型做精确比较
2.4.9 new 和 delete
2.4.10对switch语句中每个分支结尾的要求
2.4.11switch语句中的default分支
2.4.12对指针的初始化
2.4.13释放内存后的指针变量
2.4.14指针指向的数据成员的访问方式
2.5函数
2.5.1 明确函数功能
2.5.2 将重复使用的代码编写成函数
2.5.3 尽量保持函数只有唯一出口
2.5.4 函数声明和定义的格式要求
2.5.5 为函数指定返回值
2.5.6 在函数调用语句中不要使用赋值操作符
2.5.7 保护可重入函数中的全局变量