C++语言程序设计代码规范.docx
《C++语言程序设计代码规范.docx》由会员分享,可在线阅读,更多相关《C++语言程序设计代码规范.docx(16页珍藏版)》请在冰豆网上搜索。
![C++语言程序设计代码规范.docx](https://file1.bdocx.com/fileroot1/2022-12/11/19a3a36e-84f4-4e6e-b1dc-f7bf9d6b3e1e/19a3a36e-84f4-4e6e-b1dc-f7bf9d6b3e1e1.gif)
C++语言程序设计代码规范
C++语言程序设计代码规范
1命名规范
本规范对变量、函数、类(结构)等的名称有严格的规定,在编码过程中务必遵守。
1.1变量命名规范
变量名称采用匈牙利命名法,即:
完整的名称由“缀”和“主体”复合而成。
“缀”用于指示变量的种类、数值类型、作用域等属性,由小写字符和下划线(_)组成,根据其附着在“主体”的位置分为前缀和后缀两种。
“主体”表示变量的语义。
整个变量名称的格式如下:
<作用域前缀>[<指针缀>]<类型缀><主体><作用域后缀>
下面详细论述。
1.1.1作用域缀(前缀和后缀)
作用域前缀处在整个变量名的最前面。
常用的作用域前缀为:
g_
表明这是一个全局变量。
m_
表明这是一个类成员变量。
s_
表明这是一个静态(static)变量。
_(前缀)
表明这是一个局部变量。
参看后面详细解释。
_(后缀)
表明这是一个参数变量。
参看后面详细解释。
作用域后缀处在整个变量名的最后面。
只有一种情况使用作用域后缀,就是函数的形参必须以作用域后缀结束。
1.1.2指针缀
如果一个变量是指针,则必须使用指针缀。
指针缀使用字母p表示。
以前,在DOS平台下有短指针和长指针的区别,有时称长指针为lp。
在Win32平台下已经不存在这个区别了,所以统一使用p,而不是lp。
1.1.3类型缀
类型缀由小写字符构成,用于描述变量的类型。
注意:
1.不要私自创造出各种各样的前缀。
2.也没有必要在前缀中仔细区分一些细小的类型区别,那样会给代码维护工作带来额外的麻烦。
常用的类型前缀为:
n
用于一般情况下的各种整数、浮点数、枚举类型,包括:
(unsigned)int,(unsigned)long,和一些派生类型:
UINT,ULONG,WORD,DWORD等。
b
bool类型
p
表示指针,在Win32平台下使用p,而不是lp。
h
WindowsAPI内部的各种HANDLE。
sz
char或者char_w类型的数组或者字符串常量。
wnd
Windows窗口,所有MFC窗口对象都以wnd缀开头。
包括:
CView,CDialog,CFrameWnd,CButton等。
pt
POINT,CPoint
clr
COLORREF,其它用来表示颜色的数值类型
dc
CDC类
pen
CPen
brush
CBrush
vector
std:
:
vector
list
std:
:
list,CList
map
std:
:
map,CMap
array
CArray
it
std:
:
iterator
c,w,dw
用于要求明确区分数据类型长度的情况下,如跨平台的网络通讯,或磁盘读取。
注意,尽量使用n作为前缀,而不是这些字符前缀。
对于其他不在上面表中的结构、类等复杂数据类型,特别是不常使用的和不通用的,不使用前缀。
例如:
classPersonJonson;
structDateTimeMyDt;
在应用场合明确的情况下,例如:
简单的局部变量,它的值类型前缀有时可以省略。
具体见下面的例子。
1.1.4复合前缀
根据以上规则,变量根据它所在的作用域、类型、是否是指针,得到一个复合前缀。
例如:
charg_szFileName[_MAX_PATH];//全局字符串变量
char*g_pszFileName;//全局字符串指针变量:
chars_szFileName[_MAX_PATH];//静态字符串变量
char*s_pszFileName;//静态字符串指针变量:
char_s_szFileName[_MAX_PATH];//局部静态字符串变量
char*_s_pszFileName;//局部静态字符串指针变量:
charm_szFileName[_MAX_PATH];//类字符串变量
char*m_pszFileName;//类字符串指针变量:
charms_szFileName[_MAX_PATH];//类静态字符串变量
char*ms_pszFileName;//类静态字符串指针变量:
更多的例子,参见下面按照作用域讨论变量名一节。
1.1.5主体
用于描述变量的上下文意义。
一般地,由首字母大写的一个或者多个单词构成,要求用英语作为描述语言。
如:
FileName,DateTime。
这样就形成了由大小字母夹杂的单词串,这种写法常见于Windows风格的编码。
注:
全部单词小写,单词之间使用下划线分割,例如:
file_name,date_time。
这种写法常见于UNIX风格的编码。
但是这种命名方式就不能很好地区分缀和主体,所以在本规范中是不推荐的。
单个的变量声明使用单数形式,不加任何冠词。
例如:
CFile_file;
数组使用名词复数形式。
CFile_files[3];
一些容器类的作用类似于数组,所以也使用复数命名,例如:
CArray_arrayFiles;
std:
:
list_listObjects;
1.2按作用域分类讨论变量命名
1.2.1参数变量
函数的参数变量要求由后下划线结尾(见作用域缀一节)。
在一些纯数学函数中,也可省去数值类型前缀n,其它类型前缀不能省略。
例如:
boolCreate(PCTSTRpszPathName_);
doubleAdd(doublea_,doubleb_);//值类型前缀省略
1.2.2局部变量
由前下划线开头。
在纯数学函数中,或者简短的上下文中,也可省去数值类型前缀n,其它类型前缀不能省略。
bool_bRet;
char_szBuffer[_MAX_PATH]
//下面是一些值类型前缀省略的例子
int_i;//常表示循环变量
int_temp;
for(int_i=0;_i<_countof(_szBuffer);_i++)
{
float_a;//_a的作用域很短,所以可以省略
}
1.2.3全局变量
使用作用域前缀’g_’。
全局变量因为作用域很大,所以命名一定要规范。
名称的主体部分必须能清晰说明变量的意义,并且不得有不规范的缩写。
例如:
CWinAppg_Application;
intg_nVersion;
HINSTANCEg_hInstance;
1.2.4静态变量
使用作用域前缀’s_’。
局部静态变量使用前缀’_s_’,注意看下面的例子。
例如:
CNcWinApps_App;
ints_nVersion;
HINSTANCEs_hInst;
voidf()
{
staticint_s_nCallTimes;
}
1.2.5其他例子
下面是变量命名的一些例子:
externHINSTANCEg_hInst;//全局变量
staticints_nTimer=0;//全局静态变量
intfunc(intnCounter_,int*pnSize_)//参数变量
{
//局部变量
long_nTotalItem;
staticlong_s_nCount=0;
int_nVar;
LPSTR_pszBuffer;
TCHAR_szCache[_MAX_PATH];
int_var1;//省去类型前缀
}
1.3常数
目前本规范对常数类的命名规范还不是非常清晰。
很多常数作用域也很大,类似于全局变量,所以命名一定要规范。
名称的主体部分必须能清晰说明变量的意义,并且不得有不规范的缩写。
常数分成以下几类讨论。
1.3.1宏定义的常数
#define定义的常数要求用大写字母和下划线混合命名,但是并不强制要求在每个单词之间插入下划线。
如:
#defineLEFT0//okay
#defineRIGHT1//okay
#defineUP_DOWN1//okay
#defineRight1//notrecommended
1.3.2const定义的常数
(未完成)
const常数员命名既可以遵循一般变量命名法则;也可以遵循常数命名法则;
1.3.3枚举
(未完成)
枚举命名:
枚举名服从一般变量命名法则。
枚举成员命名:
枚举成员名既可以遵循一般变量命名法则;也可以遵循常数命名法则;
1.4函数命名规范
函数命名采用大小写夹杂的动宾结构命名。
如:
intGetLastError();//okay
intgetlasterror();//全小写,不推荐
intget_last_error();//全小写,不推荐
intOpenFile();//okay
intFileOpen();//非动宾结构,不推荐
属于同一类的一组函数可以使用共同前缀来标识。
如:
intNetGetError();
intNetOpen();
intNetClose();
intNetSend();
intNetReceive();
内部实现函数可以使用前下划线作为前缀,例如:
classMyClass
{
//...
private:
void_init();
};
仅在某一个代码文件使用的内部实现函数应定义为静态函数,这可以避免作用域冲突。
1.5结构命名规范
结构命名:
结构名服从一般变量命名法则。
结构成员命名:
结构变量名服从一般变量命名法则。
如:
structDateTime
{
intnYear;
intnMonth;
intnDay;
intnHour;
intnMinite;
intnSecond;
};
本规范不采用对结构成员使用表示结构的前缀。
如:
structDateTime
{
intdtYear;//error
intdtMonth;//error
intdtDay;//error
intdtHour;//error
intdtMinite;//error
intdtSecond;//error
};
一般说来,结构中不包含成员函数(偶尔,仅仅包含构造函数是允许的)。
如果希望把结构改造成包含丰富成员函数的对象,那样的话,请使用类(class)。
其命名规范见下面叙述。
1.6类(class)
1.6.1类布局
在类中,推荐先是public节的内容,然后是protected节,最后是private节。
也推荐参考MFC的类布局,使用
//Construction
//Attributes
//Operations
//Overrides
//Implementation
等注释来布局。
1.6.2类成员
类成员变量:
遵循一般变量命名法则,同时要求使用’m_’前缀。
类成员函数:
遵循一般函数命名法则;
嵌套类、枚举、嵌套结构:
遵循一般类、结构命名法则;
综合以上,举一例如:
classMyClass:
:
publicBaseClass
{
public:
//first
MyClass();
~MyClass();
protected:
//then
intm_nVar1;
intm_nVar2;
private:
//last
intDoSomething();
};
2布局规范
需要注意的是,非公共接口的结构、类、常数、函数原形不要放在公共头文件中,而是应该放在私有头文件或实现文件中。
2.1文件标头
文件标头必须包括版权说明、简短介绍。
下面是文件标头的一个例子:
//Copyright(c)NaikyCompany.Allrightsreserved.
//
//Abstract:
//
///////////////////////////////////////////////////////////
#include...
#include...
#include...
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif
自VC6.0以来,new/delete操作增加了调试版本,对检测内存泄露非常有帮助。
所以上面的代码包含这部分内容。
2.2函数说明
函数说明是可选的。
可以使用中文或者英文编写。
一般说来,公开接口、公共函数应该有说明,这样便于代码维护。
函数说明有两个地方可以放,一是放在函数声明中,而是放在函数实现中。
这两个地方的函数说明有所不同。
函数声明处的说明:
此处的说明目的是告诉使用者,该函数的用法以及应该注意的问题,应包括函数的作用、入口参数和返回值说明,以及需要注意的声明内容。
下面是一个声明处说明的例子:
//Description:
//[Youcanfillsomedescriptionhere]
//
//Entries:
//[Parameter1][aboutParameter1]
//[Parameter2][aboutParameter2]
//[Parameter3][aboutParameter3]
//
//Return:
//[aboutreturnvalue]
//[Note:
]
//[thisisanoptionalsection]
函数实现处的说明:
此处的说明目的是告诉代码维护人员,该函数实现的细节以及在实现过程中需要注意的问题。
以下是摘自实际代码的一个例子:
/****
DESCRIPTION:
Getthedistancefroma3d-pointtoa3d-line.
ALGORITHM:
Alinein3Disgivenbytheparametricvectorwithparametert:
/x0+(x1-x0)*t\
L=|y0+(y1-y0)*t|-----------------------
(1)
\z0+(z1-z0)*t/
Agivenpointis
P=(u1,v1,w1)
Thedistancebetweenthepointandthelineistherefore
r^2=(u1-x0-(x1-x0)*t)^2
+(v1-y0-(y1-y0)*t)^2
+(w1-z0-(z1-z0)*t)^2----------------------
(2)
Tominimizethedistance,take
d(r^2)/dt=0-------------------------(3)
assumethat
a=(x1-x0)u=(u1-x0)
b=(y1-y0)v=(v1-y0)
c=(z1-z0)w=(w1-z0)
therefore
-2a*(u-a*t)-2b(v-b*t)-2c(w-c*t)=0-------(4)
therefore
a*u+b*v+c*w
t=------------------------------------------(5)
a*a+b*b+c*c
referenceto
(2),get
r^2=(u-a*t)^2+(v-b*t)^2+(w-c*t)^2-----------(6)
PARAMETERS:
POINT3DDpoint_thegivenpoint
POINT3DDline0_,POINT3DDline1_thegivenline
RETURNS:
thepower2ofthedistance
****/
inlinedoubledistance2_point_line(POINT3DDpoint_,POINT3DDline0_,POINT3DDline1_)
{
//...
}
2.3代码布局
代码使用制表符缩进,制表符宽度为4。
代码行宽一般不超过80列(不过,现在的显示器越来越大,阅读更加方便,所以可以考虑把代码行宽设定到100列)。
超过的部分折行到下一行,折行要求缩进一个制表符。
2.3.1空格使用规范
保留字后面空一格。
如:
for(int_i=0;_i<3;_i++)//okey
for(int_i=0;_i<3;_i++)//notrecommended
while(true)//ok
while(true)//notrecommended
if(a==b)//ok
switch(sw)//ok
双目操作符左右各空一格,括号((,),[,])左右不空格。
如:
a=b=c;//ok
a=b=c;//notrecommended
a=(b==c)//ok
a=(b==c)//notrecommended
a=(b==c)//notrecommended
a=(b==(c&d))//notrecommended
a=b[1]//ok
a=b[1]//notrecommended
if(a==b)//ok
if(a==b)//notrecommended
单目操作符不空格
a++;//ok
++a;//ok
a*-b;//ok
~a//ok
逗号、分号前面紧贴上一个字符,后面空一格。
如:
func(inta_,intb_,intc_)//ok
func(inta_,intb_,intc_)//notrecommended
func(inta_,intb_,intc_)//notrecommended
for(int_loop=0;_loop<_MAX;_loop++)//ok
for(int_loop=0;_loop<_MAX;_loop++)//notrecommended
变量(常量)的类型、名称及其它修饰符之间使用空格,而不是制表符分开,例如:
int_nVar1=0;//ok
double_nVar2=1.0;
long_nVar3=2;
DWORD_nVar4=0xFFFF;
constfloatc_nMAX_VAL=99999.9999;
int_nVar1=0;//notrecommended
double_nVar2=1.0;
long_nVar3=2;
DWORD_nVar4=0xFFFF;
2.3.2指针符位置
指针贴近类型,而不是变量。
如:
//followinglinesarefineandrecommendedstyle!
long*_PnVar3=GetPointer();
DWORD*_nVar4=(DWORD*)0xFFFF;
constchar*_pszString=“Thisisateststring”;
//notrecommended!
long*_PnVar3=GetPointer();
DWORD*_nVar4=(DWORD*)0xFFFF;
constchar*_pszString=“Thisisateststring”;
在VC6.0环境下,我们设计了宏StandardFormat用来格式化代码。
可以完成大部分格式化工作。
也可以用VC++中Edit|Advanced|TabifySelection和Edit|Advanced|UntabifySelection命令来格式化代码。
下面是一些推荐布局风格:
//Ex.1
if(a==b)
{
//somecodehere
}
//Ex.2
switch(_nSwitchVar)
{
case1:
{
//somecodehere
int_temp=//...
}
break;
case2:
f
(2);
break;
case3:
f(3);
break;
default:
assert(false);
break;
}
不推荐风格:
if(a==b){
//somecodehere
}
3语法风格
避免不好的语法习惯。
3.1关于if
不要在if表达式中使用’=’。
例如:
int_a;
if(_a=GetValue())
{
//somecodehere
}
应该写为:
int_a=GetValue();
if(_a)//orif(_a!
=0)
{
//somecodehere
}
下面的代码实际上可能并不按你想象的方式运行:
if(a==b)
if(d==e)
x=1;
else
func();
3.2变量声明与定义
不要使用未赋初值的变量,尤其是指针:
int_a;
if(GetSomeValue()==OK)
_a=100;
Func(a);//atsomecases,“a”hasnotgetaninitialvaluehere
3.3关于宏
不要在宏中使用表达式或者调用函数:
#define__max(a,b)((a)>(b)?
(a):
(b))
__max(func(),3)//notrecommended!
!
!
__max(var++,3)//notrecommended!
!
!
int_a=func();
__max(_a,3)//okey
尽量使用inline函数代替函数宏。
尽量使用const代替常数宏。
3.4测试代码
一些测试代码要用_DEBUG包围起来。
//badcode!
!
!
if(pszBuffer)
{
ASSERT(strlen(pszBuffer)<100);
}
//goodcode
#ifdef_DEBUG
if(pszB