C++编码规范.docx
《C++编码规范.docx》由会员分享,可在线阅读,更多相关《C++编码规范.docx(54页珍藏版)》请在冰豆网上搜索。
C++编码规范
编程规范的说明
AnIntroductiontoC/C++
CodingConventions
沈阳航空航天大学军工行业信息与安全应用实验室
2013年3月
为了提高软件开发质量,降低开发周期,增强代码的可重用性和易读性,使软件便于维护,开发人员间便于交流和协作,特总结出开发规范,以为参考。
一说明
1.1为什么要有编码规范
编码规范对于程序员而言尤为重要,有以下几个原因:
◆一个软件的生命周期中,80%的花费在于维护。
◆几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护。
◆编码规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码。
◆如果你将源码作为产品发布,就需要确任它是否被很好的打包并且清晰无误,一如你已构建的其它任何产品。
为了执行规范,每个软件开发人员必须一致遵守编码规范。
每个人!
!
!
1.2总体要求
开发的系统具有较强的通用性、申缩性,并有较强的响音速度。
同时开发过程中必须严格按照规范,以便于管理和协同开发。
通用性:
能适应机构变动。
伸缩性:
程序模块化,程序模块能进行任何组合。
规范性:
截面统一,原程序和SQL文件便于他人阅读。
1.3版权说明
本书的大部分内容取材于上海贝尔林锐博士的《高质量C++/C编程指南》,现整理汇编成为沈阳航空工业学院计算机学院网络信息安全实验室的内部编程规范,也可作为培训教材。
二 命名规范
命名应尽量使用匈牙利命名法,该命名规则的主要思想是“在变量和函数名中加入前缀以增进人们对程序的理解”。
例如所有的字符变量均以ch为前缀,若是指针变量则追加前缀p。
如果一个变量由ppch开头,则表明它是指向字符指针的指针。
变量名或函数名中使用大写字符来区分各个部分,以便于记忆和阅读。
如bPatchMinute, DeleteDirInfo()。
全局(包括类中的)变量用长名字,局部变量用短名字。
匈牙利记法。
即:
前缀+类型+变量名
1)格式:
[m_|s_|g_]type[classname|structname]variablename
2)解释:
·m_:
类的成员变量
·ms_:
类的静态成员变量
·s_:
静态全局变量
·g_:
普通全局变量
2.1变量
【规则2-1-1】标识符应当直观且可以拼读,可望文知意,不必进行“解码”。
标识符最好采用英文单词或其组合,便于记忆和阅读。
切忌使用汉语拼音来命名。
程序中的英文单词一般不会太复杂,用词应当准确。
例如不要把CurrentValue写成NowValue。
【规则2-1-2】标识符的长度应当符合“min-length&&max-information”原则。
单字符的名字如i,j,k,m,n,x,y,z等,它们通常可用作函数内的局部变量。
局部变量应尽量易懂简洁,使用常见的变量,如
Num,nCount,i,j,k,n,len,pos, offset,nReadNum,index,nRet,ret, string,filename
临时变量,如ltmp,ftmp,tmpStr,tempStr。
【规则2-1-3】命名规则尽量与所采用的操作系统或开发工具的风格保持一致。
例如Windows应用程序的标识符通常采用“大小写”混排的方式,如AddChild。
而Unix应用程序的标识符通常采用“小写加下划线”的方式,如add_child。
别把这两类风格混在一起用。
【规则2-1-4】程序中不要出现仅靠大小写区分的相似的标识符。
例如:
intx,X;//变量x与X容易混淆
voidfoo(intx);//函数foo与FOO容易混淆
voidFOO(floatx);
【规则2-1-5】程序中不要出现标识符完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但会使人误解。
【规则2-1-6】如果命名使用缩写,则应该使用《通用缩写表》(见附录)
【规则2-1-7】变量的名字应当使用“名词”或者“形容词+名词”或者“名词+动词”。
例如:
floatvalue;
floatoldValue;
nodeobjFind;
【规则2-1-8】变量和参数用小写字母开头的单词组合而成。
例如:
BOOLbFlag;
intiDrawMode;
【规则2-1-9】常量全用大写的字母,用下划线分割单词。
例如:
constintMAX=100;
constintMAX_LENGTH=100;
【规则2-1-10】为了防止某一软件库中的一些标识符和其它软件库中的冲突,可以为各种标识符加上能反映软件性质的前缀。
例如三维图形标准OpenGL的所有库函数均以gl开头,所有常量(或宏定义)均以GL开头。
【建议2-1-1】尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号。
这是为了防止程序员偷懒,不肯为命名动脑筋而导致产生无意义的名字(因为用数字编号最省事)。
2.2宏、结构体
【规则2-2-1】宏命名、枚举名、联合名和typedef定义类型应详细,避免重复,一律为大写。
例如:
#define DEL_EMPTY(a) {if (a) {delete a;a=NULL;}}
#define SUCCESS 0
#define FAIL -1
【规则2-2-2】自定义消息从WM_USER开始。
#define MYAPP_MESSAGE WM_USER+0x1001
【规则2-2-3】结构体类型命名必须全部用大写字母,原则上前面以下划线开始;结构体变量命名必须用大小写字母组合,第一个字母必须使用大写字母,必要时可用下划线间隔。
对于私有数据区,必须注明其所属的进程。
全局数据定义只需注意其用途。
例如:
typedefstruct
{
charchProductName[20];
charchAuthor[20];
unsignedlongulMaxTables;
unsignedlongulUsedTables;
}_DBS_DATABASE;
_DBS_DATABASEGdataBase;
2.3枚举、联合、类
【规则2-3-1】枚举名加小写前缀"enum",联合名加小写前缀"uni"。
例如:
typedefenum_KFILE_OPEN_MODE
{
enumOPEN_READONLY=0,
enumOPEN_READWRITE=1,
enumCREATE_ALWAY=3
}KFILE_OPEN_MODE;
typedefunion_VARIANT
{
charunichVal;
intuninVal;
longunilVal;
floatuniftVal;
}VARIANT;
【规则2-3-2】类名必须以大写"C"开头,代表class。
后面字母反映具体含义,以清晰表达类的用途和功能为原则。
接口必须以大写"I"开头,代表Interface。
当名称由多个单词构成时,每一个单词的第一个字母必须大写。
【规则2-3-3】 以Class声明的类,都必须以名词或名词短语命名,体现类的作用。
如:
ClassCIndicator
【规则2-3-4】 当类是一个特性(Attribute)时,以Attribute结尾,当类是一个异常(Exception)时,以Exception结尾。
ClassCColorSetException
ClassCCauseExceptionAttribute
【规则2-3-5】 当类只需有一个对象实例(全局对象,比如Application等),必须以Class结尾。
ClassCScreenClass
ClassCSystemClass
【规则2-3-6】 当类只用于作为其他类的基类,根据情况,以Base结尾。
ClassCIndicatorBase
【规则2-3-7】 如果定义的类是一个窗体,那么名字的后面必须加后缀Frm,如果是Web窗体,必须加后缀Page。
ClassCInheritsFrm/*Windows窗体*/
ClassCInheritsPage/*Web窗体*/
【规则2-3-8】 类力求封装好,严格区分public,private,protect等作用域,如果一个函数与本类有莫大的关系,可以作为该类的静态成员函数,不用或少用友元函数等破坏类封装性的方法和技巧。
如果一些结构或宏仅与本类有关,可在类头文件中定义。
2.4函数
【规则2-4-1】 全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。
类的成员函数应当只使用“动词”,被省略掉的名词就是对象本身。
例如:
DrawBox();//全局函数
box->Draw();//类的成员函数
【规则2-4-2】 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。
例如:
intiMinValue;
intiMaxValue;
intSetValue(…);
intGetValue(…);
【规则2-4-2】 函数命名应该见名知意。
如CalcAllDataStyle(),ReadDocDataFromTime(),GetIndexInfo()等。
常见的函数:
Init, OpenAll,,Create_,Get_, Set_, Read_, Load_, Write_, Start_,Stop_,
Check_, Test_, Fill_, Process_, Sort_, Do_,Select_,Is_, Exist_,_Ex。
【规则2-4-3】 函数名第一个字母必须大写,全局函数必须以小写前缀"g"开头,函数名最长不得超过30个字符。
【规则2-4-4】 函数原型说明包括引用外来函数及内部函数,外部引用必须在右侧注明函数来源:
模块名及文件名,如是内部函数,只要注释其定义文件名。
三程序版式
版式虽然不会影响程序的功能,但会影响可读性。
程序的版式追求清晰、美观,是程序风格的重要构成因素。
可以把程序的版式比喻为“书法”。
好的“书法”可让人对程序一目了然,看得兴致勃勃。
差的程序“书法”如螃蟹爬行,让人看得索然无味,更令维护者烦恼有加。
3.1空行
空行起着分隔程序段落的作用。
空行得体(不过多也不过少)将使程序的布局更加清晰。
空行不会浪费内存,虽然打印含有空行的程序是会多消耗一些纸张,但是值得。
所以不要舍不得用空行。
【规则3-1-1】在每个类声明之后、每个函数定义结束之后都要加空行。
参见示例3-1(a)
【规则3-1-2】在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。
参见示例3-1(b)
//空行
voidFunction1(…)
{
…
}
//空行
voidFunction2(…)
{
…
}
//空行
voidFunction3(…)
{
…
}
//空行
while(condition)
{
statement1;
//空行
if(condition)
{
statement2;
}
else
{
statement3;
}
//空行
statement4;
}
示例3-1(a)函数之间的空行示例3-1(b)函数内部的空行
3.2代码行
【规则3-2-1】一行代码只做一件事情,如只定义一个变量,或只写一条语句。
这样的代码容易阅读,并且方便于写注释。
【规则3-2-2】if、for、while、do等语句自占一行,执行语句不得紧跟其后。
不论执行语句有多少都要加{}。
这样可以防止书写失误。
intwidth;//宽度
intheight;//高度
intdepth;//深度
intwidth,height,depth;//宽度高度深度
x=a+b;
y=c+d;
z=e+f;
X=a+b;y=c+d;z=e+f;
if(width{
dosomething();
}
if(widthfor(initialization;condition;update)
{
dosomething();
}
//空行
other();
for(initialization;condition;update)
dosomething();
other();
示例3-2(a)风格良好的代码行示例3-2(b)风格不良的代码行
【建议3-2-1】尽可能在定义变量的同时初始化该变量(就近原则)。
如果变量的引用处和其定义处相隔比较远,变量的初始化很容易被忘记。
如果引用了未被初始化的变量,可能会导致程序错误。
本建议可以减少隐患。
3.3代码行内的空格
【规则3-3-1】关键字之后要留空格。
象const、virtual、inline、case等关键字之后至少要留一个空格,否则无法辨析关键字。
象if、for、while等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。
【规则3-3-2】函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。
【规则3-3-3】‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。
【规则3-3-4】‘,’之后要留空格,如Function(x,y,z)。
如果‘;’不是一行的结束符号,其后要留空格,如for(initialization;condition;update)。
【规则3-3-5】赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=”“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格。
【规则3-3-6】一元操作符如“!
”、“~”、“++”、“--”、“&”(地址运算符)等前后不加空格。
【规则3-3-7】象“[]”、“.”、“->”这类操作符前后不加空格。
【规则3-3-7】类型强制转换时,‘(’‘)’前后不得有空格。
例:
可写做:
(KSFile*)pFile;
也可写做:
(KSFile*)pFile
不得写做:
(KSFile*)pFile
(KSFile*)pFile
【建议3-3-1】对于表达式比较长的for语句和if语句,为了紧凑起见可以适当地去掉一些空格,如for(i=0;i<10;i++)和if((a<=b)&&(c<=d))
voidFunc1(intx,inty,intz);//良好的风格
voidFunc1(intx,inty,intz);//不良的风格
if(year>=2000)//良好的风格
if(year>=2000)//不良的风格
if((a>=b)&&(c<=d))//良好的风格
if(a>=b&&c<=d)//不良的风格
for(i=0;i<10;i++)//良好的风格
for(i=0;i<10;i++)//不良的风格
for(i=0;I<10;i++)//过多的空格
x=a
a:
b;//良好的风格
x=a
a:
b;//不好的风格
int*x=&y;//良好的风格
int*x=&y;//不良的风格
array[5]=0;//不要写成array[5]=0;
a.Function();//不要写成a.Function();
b->Function();//不要写成b->Function();
示例3-3代码行内的空格
3.4对齐
【规则3-4-1】程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。
【规则3-4-2】{}之内的代码块在‘{’右边数格处左对齐。
嵌套的代码块每进一套,缩进一个tab,TAB为4个空格。
voidFunction(intx)
{
…//programcode
}
voidFunction(intx){
…//programcode
}
if(condition)
{
…//programcode
}
else
{
…//programcode
}
if(condition){
…//programcode
}
else{
…//programcode
}
for(initialization;condition;update)
{
…//programcode
}
for(initialization;condition;update){
…//programcode
}
While(condition)
{
…//programcode
}
while(condition){
…//programcode
}
如果出现嵌套的{},则使用缩进对齐,如:
{
…
{
…
}
…
}
示例3-4(a)风格良好的对齐示例3-4(b)风格不良的对齐
3.5长行拆分
【规则3-5-1】代码行最大长度宜控制在70至80个字符以内。
代码行不要过长,否则眼睛看不过来,也不便于打印。
【规则3-5-2】长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。
拆分出的新行要进行适当的缩进,使排版整齐,语句可读。
if((very_longer_variable1>=very_longer_variable12)
&&(very_longer_variable3<=very_longer_variable14)
&&(very_longer_variable5<=very_longer_variable16))
{
dosomething();
}
virtualCMatrixCMultiplyMatrix(CMatrixleftMatrix,
CMatrixrightMatrix);
for(very_longer_initialization;
very_longer_condition;
very_longer_update)
{
dosomething();
}
示例3-5长行的拆分
3.6修饰符的位置
修饰符*和&应该靠近数据类型还是该靠近变量名,是个有争议的活题。
若将修饰符*靠近数据类型,例如:
int*x;从语义上讲此写法比较直观,即x是int类型的指针。
上述写法的弊端是容易引起误解,例如:
int*x,y;此处y容易被误解为指针变量。
虽然将x和y分行定义可以避免误解,但并不是人人都愿意这样做。
【规则3-6-1】应当将修饰符*和&紧靠变量名
例如:
char*name;
int*x,y;//此处y不会被误解为指针
3.7注释
C语言的注释符为“/*…*/”。
C++语言中,程序块的注释常采用“/*…*/”,行注释一般采用“//…”。
原则上注释要求使用中文,注释通常用于:
(1)版本、版权声明;
(2)函数接口说明;
(3)重要的代码行或段落提示。
虽然注释有助于理解代码,但注意不可过多地使用注释。
参见示例3-6。
【规则3-7-1】注释是对代码的“提示”,而不是文档。
程序中的注释不可喧宾夺主,注释太多了会让人眼花缭乱。
注释的花样要少。
【规则3-7-2】如果代码本来就是清楚的,则不必加注释。
否则多此一举,令人厌烦。
例如
i++;//i加1,多余的注释
【规则3-7-3】边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。
不再有用的注释要删除。
【规则3-7-4】注释应当准确、易懂,防止注释有二义性。
错误的注释不但无益反而有害。
【规则3-7-5】尽量避免在注释中使用缩写,特别是不常用缩写。
【规则3-7-6】注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不可放在下方。
【规则3-7-8】当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读
/*
*函数介绍:
*输入参数:
*输出参数:
*返回值:
*/
voidFunction(floatx,floaty,floatz)
{
…
}
if(…)
{
…
while(…)
{
…
}//endofwhile
…
}//endofif
示例3-6程序的注释
3.8类的版式
类可以将数据和函数封装在一起,其中函数表示了类的行为(或称服务)。
类提供关键字public、protected和private,分别用于声明哪些数据和函数是公有的、受保护的或者是私有的。
这样可以达到信息隐藏的目的,即让类仅仅公开必须要让外界知道的内容,而隐藏其它一切内容。
我们不可以滥用类的封装功能,不要把它当成火锅,什么东西都往里扔。
类的版式主要有两种方式:
(1)将private类型的数据写在前面,而将public类型的函数写在后面,如示例3-7(a)。
采用这种版式的程序员主张类的设计“以数据为中心”,重点关注类的内部结构。
(2)将public类型的函数写在前面,而将private类型的数据写在后面,如示例3-7(b)采用这种版式的程序员主张类的设计“以行为为中心”,重点关注的是类应该提供什么样的接口(或服务)。
【建议3-8-1】采用“以行为为中心”的书写方式。
classA
{
private:
inti,j;
floatx,y;
…
public:
voidFunc1(void);
voidFunc2(void);
…
}
classA
{
public:
voidFunc1(void);
voidFunc2(void);
…
private:
inti,j;
floatx,y;
…
}
示例3-7(a)以数据为中心版式示例3-7(b)以行为为中心的版式
【规则3-8-1】类的成员变量在构造函数或初始化函数中应赋初值,指针在构造函数中赋NULL,析构时DEL_EMPTY它,以免内存泄露。
【规则3-8-2】如果一个函数与本类有莫大的关系,可以作为该类的静态成员函数,不用或少用友元函数等破坏类封装性的方法和技巧。
【建议3-8-2】如果一些结构或宏仅与本类有关,可在类头文件中定义。
3.9函数的版式
【规则3-9-1】一个用于设置输入参数的例程应