ZN22 软件编码规范指南CC++.docx
- 文档编号:24248072
- 上传时间:2023-05-25
- 格式:DOCX
- 页数:27
- 大小:29.59KB
ZN22 软件编码规范指南CC++.docx
《ZN22 软件编码规范指南CC++.docx》由会员分享,可在线阅读,更多相关《ZN22 软件编码规范指南CC++.docx(27页珍藏版)》请在冰豆网上搜索。
ZN22软件编码规范指南CC++
Q/HSNW-ZN-22
软件设计编码规范指南
_C/C++语言
编制:
年 月 日
审核:
年 月 日
批准:
年 月 日
修订历史记录
版本
作者
参与者
起止日期
备注
1.0
万思军
2005-10-27
讨论通过本规范
1.1
万思军
2005-11-15
添加版本管理部分
1.2
万思军
2006-6-7
重新修订注释方式,进行简化。
制表符的使用定义
1.3
万建林
2009-8-10
修订版本管理,进行简化。
目录
1简介4
1.1目的4
1.2范围和说明4
1.3定义、首字母缩写词和缩略语4
1.4参考资料4
2文件结构5
2.1头文件5
2.2内联函数定义文件5
2.3实现文件5
2.4版本管理6
3命名规则7
3.1类/结构7
3.2函数7
3.3变量8
3.4常量9
3.5宏、枚举值9
4代码风格与版式10
4.1类/结构11
4.2函数13
4.3变量、常量15
4.4宏15
5附录17
5.1常用注释一览17
5.1.1文件头注释17
5.1.2标准类注释17
5.1.3标准函数注释18
5.1.4语句/函数组18
5.1.5语句块18
5.1.6分割带18
简介
1.1目的
软件设计编码规范的目的是说明如何编写代码的一般准则,及使用编程语言时将要用到的约定。
使软件开发在语法上和功能上正确;具有良好的结构和风格。
提高程序的可靠性、可读性、可修改性、可维护性、一致性。
1.2范围和说明
本规范面向使用MFC和ACE类库的C++项目制定,项目所开发的代码必须遵守本规范中的约定,并作为对代码质量的一个评价标准,其他项目可以根据项目使用的开发包的特点进行裁剪与定义。
对于使用MFC类库和ACE类库的系统,为了保证和原有系统的融合,看上去像一个人编写出来的,我们对命名规则和代码风格与版式部分进行了有差别定义。
但其他部分应遵守相同的约定。
注释风格采用Doxygen风格的注释,以便以后能自动产生文档。
强制规定一个制表符为4个半角空格符,并且在源文件中不保留制表符,而以4个半空格符替代。
如果在使用中使用制表符进行对齐,而要在保存时保存4个半空格符,可以在相应的编辑器的配置中进行配置。
(这样可以避免不同编辑器对制表符的不同默认定义引发的代码排版混乱问题。
)
本文档中的编码规范都以:
规则(或建议)
解释
的格式给出,其中强制性规则使用黑色,建议性规则使用灰色。
1.3定义、首字母缩写词和缩略语
术语
解释
API
应用程序编程接口
UI
用户界面
GUI
图形用户界面
1.4参考资料
名称
作者
发布日期
GC_GF16软件设计编码规范(C&C++)
李月高
2003
高质量C++/C编程指南
林锐博士
2001
C++编码规范与指导
白杨
2009-05-07
Doxygen_manual_1.4.6
2006
文件结构
1.5头文件
头文件通常由以下几部分组成:
文件头注释
每个头文件,无论是内部的还是外部的,都应该由一个规范的文件头注释作为开始。
预处理块
为了防止头文件被重复引用,应当用ifndef/define/endif结构产生预处理块。
对于采用MFC类库的程序,可以延用框架自动生成的#progmaonce
函数和类/结构的声明等
声明模块的接口
需要包含的内联函数定义文件(如果有的话)
如果类中的内联函数较多,或者一个头文件中包含多个类的定义(不推荐),可以将所有内联函数定义放入一个单独的内联函数定义文件中,并在类声明之后用“#include”指令把它包含进来。
头文件的编码规则:
分割多组接口(如果有的话)
如果在一个头件中定义了多个类或者多组接口(不推荐),为了便于浏览,应该在每个类/每组接口间使用分割带把它们相互分开。
关于头文件的完整例子,请参见附录:
头文件例子
1.6内联函数定义文件
如上所述,在内联函数较多的情况下,为了避免头文件过长、版面混乱,可以将所有的内联函数定义移到一个单独的文件中去,然后再用#include指令将它包含到类声明的后面。
这样的文件称为一个内联函数定义文件。
按照惯例,应该将这个文件命名为“filename.inl”,其中“filename”与相应的头文件和实现文件相同。
内联函数定义文件由以下几部分组成:
文件头注释
每内联函数定义文件都应该由一个规范的文件头注释作为开始
内联函数定义
内联函数的实现体
内联函数定义文件的编码规则:
分割多组接口(如果有的话)
如果在一个内联函数定义文件中定义了多个类或者多组接口的内联函数(不推荐),必须在每个类/每组接口间使用分割带把它们相互分开。
关于内联函数定义文件的完整例子,请参见附件:
内联函数定义文件例子
1.7实现文件
实现文件包含所有数据和代码的实现体。
实现文件的格式为:
文件头注释
每个实现文件都应该由一个规范的文件头注释作为开始
对配套头文件的引用
引用声明了此文件实现的类、函数及数据的头文件
对一些仅用于实现的头文件的引用(如果有的话)
将仅与实现相关的接口包含在实现文件里(而不是头文件中)是一个非常好的编程习惯。
这样可以有效地屏蔽不应该暴露的实现细节,将实现改变对其它模块的影响降低到最少。
程序的实现体
数据和函数的定义
实现文件的编码规则:
分割每个部分
在本地(静态)定义和外部定义间,以及不同接口或不同类的实现之间,应使用分割带相互分开。
关于实现文件的完整例子,请参见:
实现文件例子
1.8版本管理
对于使用微软VisualStudio编译的程序,可执行文件的程序版本统一采用VisualStudio的资源文件(*.rc)进行配置、更改和管理。
Windows界面程序
直接修改资源文件的VS_VERSION_INFO部分。
无资源文件控制台程序
先手动添加资源文件,然后修改VS_VERSION_INFO部分。
变更记录
文件头注释中记录每次代码改动,每个源文件单独维护版本,初始版本从1.0.1开始,主版本号一般不进行变更;每次新增函数则副版本号加1,每次修订发布号加1。
命名规则
在引入细节之前,先说明一下命名规范的整体原则:
同一性
在编写一个子模块或派生类的时候,要遵循其基类或整体模块的命名风格,保持命名风格在整个模块中的同一性。
标识符组成
标识符采用英文单词或其组合,应当直观且可以拼读,可望文知意,用词应当准确。
最小化长度&&最大化信息量原则
在保持一个标识符意思明确的同时,应当尽量缩短其长度。
避免过于相似
不要出现仅靠大小写区分的相似的标识符,例如“i”与“I”,“function”与“Function”等等。
避免在不同级别的作用域中重名
程序中不要出现名字完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但容易使人误解。
正确命名具有互斥意义的标识符
用正确的反义词组命名具有互斥意义的标识符,如:
"nMinValue"和"nMaxValue","GetName()"和"SetName()"....
避免名字中出现数字编号
尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号。
1.9类/结构
MFCC++类/结构的命名应该遵循以下准则:
MFCC++类/结构的命名
类的名称都要以大写字母“C”开头,后跟一个或多个单词。
为便于界定,每个单词的首字母要大写。
为保持模块内的同一性,使用ACE类库的命名规则为:
使用ACE类库的命名
使用ACE类库的以系统模块的标示开头,后跟一个或多个单词,单词间使用首字母大写+下划线界定,例如:
"APTS_Service_Status"
1.10函数
MFCC++类的函数应该遵循以下准则:
函数的命名
函数的名称由一个或多个单词组成。
为便于界定,每个单词的首字母要大写。
推荐的组成形式
每一个函数通常执行一种操作行为,所以其命名应清晰的体现所完成的工作,所以函数名应当使用"动词"或者"动词+名词"(动宾词组)的形式。
存取类属性的成员函数:
1、如果是访问类的属性并返回,命名以get开头,如果返回值是boolean,以is开头。
2、设置类属性,命名以set开头。
例如:
GetName(),IsLimit(),SetName()。
虚函数
虚函数习惯以“Do”开头,如:
"DoRefresh()",DoEncryption()"....
回调和事件处理函数
回调和事件处理函数习惯以单词“On”开头。
例如:
"OnTimer()","OnExit()"
ACEC++类的函数应该遵循以下准则:
函数的命名
函数的名称由一个或多个单词组成,单词全部为小写字母。
为便于界定,每个单词的用下划线分隔。
推荐的组成形式
每一个函数通常执行一种操作行为,所以其命名应清晰的体现所完成的工作,所以函数名应当使用"动词"或者"动词+名词"(动宾词组)的形式。
存取类属性的成员函数:
1、如果是访问类的属性并返回,命名以get开头,如果返回值是boolean,以is开头。
2、设置类属性,命名以set开头。
例如:
get_name(),is_limit(),set_name()。
虚函数
虚函数习惯以“do”开头,如:
"do_refresh()","do_encryption()"
回调和事件处理函数
回调和事件处理函数习惯以单词“handle_”开头。
例如:
"handle_timer()","handle_exit()"
1.11变量
变量应该是程序中使用最多的标识符了,变量的命名规范可能是一套C++命名准则中最重要的部分:
变量的命名
变量名由作用域前缀+类型前缀+一个或多个单词组成。
对于MFCC++为便于界定,每个单词的首字母要大写。
对于ACEC++为便于界定,每个单词使用下划线分隔。
对于某些用途简单明了的局部变量,也可以使用简化的方式,如:
i,j,k,x,y,z....
作用域前缀
作用域前缀标明一个变量的可见范围。
作用域可以有如下几种:
前缀
说明
无
局部变量
m_
类的成员变量(member)
sm_
类的静态成员变量(staticmember)
s_
静态变量(static)
g_
外部全局变量(global)
sg_
静态全局变量(staticglobal)
gg_
进程间共享的共享数据段全局变量(globalglobal)
除非不得已,否则应该尽可能少使用全局变量。
ACEC++使用后缀下划线表示成员变量。
类型前缀
类型前缀标明一个变量的类型,可以有如下几种:
前缀
说明
i
整型和位域变量(intger)
e
枚举型变量(enumeration)
c
字符型变量(char)
u
无符号整型变量(unsignedint)
si
短整型变量(short)
b
布尔型变量(bool)
l
长整型变量(long)
ul
无符号长整型变量(unsignedlong)
d
双浮点型(double)
by
字节变量(byte)
str,s
字符串变量(cstring)
h
句柄变量(handle)
sz
以0字符结尾的字符串
f
浮点型变量(float)
p
指针型变量和迭代子(pointer)
pfn
特别针对指向函数的指针变量和函数对象指针(pointeroffunction)
a
数组(array)
其他
对于经常用到的类,也可以定义一些专门的前缀,如:
,std:
:
vector类的前缀可以定义为"v"等等。
对于其他未定义的类型如结构体,可以自定义,如:
使用tag来标识。
类型前缀可以组合使用,例如"ac"表示字符数组,"ppn"表示指向整型的指针的指针等等。
对在同一行定义多个变量有一种约定,即在C++中指针修饰符仅使用于最接近的变量,而不是所有的变量。
推荐的组成形式
变量的名字应当使用"名词"或者"形容词+名词"。
例如:
"iMaxWidth"
1.12常量
常量的命名
常量名由全大写字母组成,单词间通过下划线来界定,如:
DELIMITER,MAX_BUFFER....
类型前缀的定义与变量命名规则中的相同。
1.13宏、枚举值
宏、枚举值的命名
宏和枚举值由全大写字母组成,单词间通过下划线来界定,当枚举作为常量定义,并且未包含在类中时,必须在标识值前使用前缀以防止名字冲突。
若无前缀,则可能与其他已定义的值冲突如:
ERROR_UNKNOWN,OP_STOP....
代码风格与版式
代码风格的重要性怎么强调都不过分。
一段稍长一点的无格式代码基本上是不可读的。
先来看一下这方面的整体原则:
空行的使用
空行起着分隔程序段落的作用。
空行得体(不过多也不过少)将使程序的布局更加清晰。
空行不会浪费内存,虽然打印含有空行的程序是会多消耗一些纸张,但是值得。
所以不要舍不得用空行。
∙在每个类声明之后、每个函数定义结束之后都要加1行空行。
∙在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。
语句与代码行
∙一行代码只做一件事情,如只定义一个变量,或只写一条语句。
这样的代码容易阅读,并且方便于写注释。
∙"if"、"for"、"while"、"do"、"try"、"catch"等语句自占一行,执行语句不得紧跟其后。
不论执行语句有多少都要加"{}"。
这样可以防止书写失误。
缩进和对齐
∙程序的分界符"{"和"}"应独占一行并且位于同一列,同时与引用它们的语句左对齐。
∙"{}"之内的代码块在"{"右边一个制表符(4个半空格符)处左对齐。
如果出现嵌套的"{}",则使用缩进对齐。
最大长度
代码行最大长度宜控制在70至80个字符以内。
代码行不要过长,否则眼睛看不过来,也不便于打印。
长行拆分
长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。
拆分出的新行要进行适当的缩进,使排版整齐,语句可读。
例如:
if((very_longer_variable1>=very_longer_variable2)
&&(very_longer_variable3<=very_longer_variable4)
&&(very_longer_variable5<=very_longer_variable6))
{
dosomething();
}
空格的使用
∙关键字之后要留空格。
象"const"、"virtual"、"inline"、"case"等关键字之后至少要留一个空格,否则无法辨析关键字。
象"if"、"for"、"while"、"catch"等关键字之后应留一个空格再跟左括号"(",以突出关键字。
∙函数名之后不要留空格,紧跟左括号"(",以与关键字区别。
∙"("向后紧跟。
而")"、","、";"向前紧跟,紧跟处不留空格。
∙","之后要留空格,如Function(x,y,z)。
如果";"不是一行的结束符号,其后要留空格,如for(initialization;condition;update)。
∙赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如"="、"+="">="、"<="、"+"、"*"、"%"、"&&"、"||"、"<<","^"等二元操作符的前后应当加空格。
∙一元操作符如"!
"、"~"、"++"、"--"、"&"(地址运算符)等前后不加空格。
∙象"[]"、"."、"->"这类操作符前后不加空格。
修饰符的位置
∙为便于理解,应当将修饰符"*"和"&"紧靠数据类型。
例如:
char*name;
int*x,
y; //为避免y被误解为指针,这里必须分行写。
int*Function(void*p);
注释
∙注释的位置应与被描述的代码相邻,可以放在代码的上方,不可放在下方或右方,。
∙边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。
不再有用的注释要删除。
∙注释应当准确、易懂,防止注释有二义性。
∙当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。
与常量的比较
在与宏、常量进行"==","!
=",">=","<="等比较运算时,应当将常量写在运算符左边,而变量写在运算符右边。
这样可以避免因为偶然写错把比较运算变成了赋值运算的问题。
例如:
//如果把"=="错打成"=",编译器就会报错
if(NULL==p)
{
//...
}
1.14类/结构
类是C++中最重要也是使用频率最高的新特性之一。
类的版式好坏将极大地影响代码品质。
注释头与类声明
与文件一样,每个类应当有一个注释头用来说明该类的各个方面。
类声明换行紧跟在注释头后面,"class"关键字由行首开始书写,后跟类名称。
界定符"{"和"};"应独占一行,并与"class"关键字左对齐。
/**
*@class类名称
*
*@brief类功能的简要说明
*
*类功能的详细描述
*/
classCXXX
{
//...
};
对于功能明显的简单类(接口小于10个),也可以使用简单的单行注释头:
///<简要说明该类所完成的功能>
classCXXX
{
//...
};
继承
基类直接跟在类名称之后,不换行,访问说明符(public,private,或protected)不可省略。
如:
classCXXX:
publicCAAA,privateCBBB
{
//...
};
以行为为中心
将公有的定义和成员放在类声明的最前面,保护的放在中间,而私有的摆在最后。
访问说明符
访问说明符(public,private,或protected)应该独占一行,并与类声明中的‘class’关键字左对其。
类成员的声明版式
对于比较复杂(成员多于20个)的类,其成员必须分类声明。
每类成员的声明由访问说明符(public,private,或protected)+全行注释开始。
注释不满全行(80个半角字符)的,由"/"字符补齐,最后一个"/"字符与注释间要留一个半角空格符。
如果一类声明中有很多组功能不同的成员,还应该用分组注释将其分组。
分组注释也要与"class"关键字对其。
每个成员的声明都应该由"class"关键字开始向右缩进一个制表符(4个半角空格符),成员之间左对其。
例如:
classCXXX
{
public:
/////////////////////////////////////////////////////////////类型定义
typedefvector
public:
/////////////////////////////////////////////////////////////构造、析构、初始化
CXXX();
~CXXX();
public:
/////////////////////////////////////////////////////////////公用方法
//@{功能组1
voidFunction1(void)const;
longFunction2(intn);
//@}功能组1
//@{功能组2
voidFunction3(void)const;
boolFunction4(int&n);
//@}功能组2
private:
//////////////////////////////////////////////////////////////////////////属性
//...
private:
////////////////////////////////////////////////////////////////////禁用的方法
//禁止复制
CXXX(constCXXX&rhs);
CXXX&operator=(constCXXX&rhs);
};
嵌套的类声明
在相应的逻辑关系确实存在时,类声明可以嵌套。
嵌套类可以使用简单的单行注释头:
classCXXX
{
///嵌套类说明
calssCYYY
{
//...
};
};
内联函数的实现体
定义在类声明之中的函数将自动成为内联函数。
但为了使类的声明更为清晰明了,应尽量避免直接在声明中直接定义成员函数的编程风格。
鼓励使用"inline"关键字将内联函数放在类声明的外部定义。
关于类声明的例子,请参见:
类/结构的风格与版式例子
1.15函数
函数是程序执行的最小单位,任何一个有效的C/C++程序都少不了函数。
函数原型
函数原型的格式为:
[存储类]返回值类型
[名空间或类]:
:
函数名(参数列表)[const说明符][异常过滤器]
例如:
int
CSem:
:
Function2(constchar*pcName)constthrow(Exp)
其中:
∙以"[]"括住的为可选项目。
∙除了构造/析构函数外,"返回值类型"和"参数列表"项不可省略(可以为"void")。
∙"const说明符"仅用于成员函数中
∙"存储类"的说明见下文
函数声明
函数声明的格式为:
///函数功能简单说明(可选)
函数原型;
函数声明和其它代码间要有空行分割。
声明成员函数时,为了紧凑,返回值类型和函数名之间不用换行.
函数定义
函数定义使用如下格式:
/**
*标准函数注释
*函数功能参数描述等
*/
函数原型
{
//...
}
对于返回值、参数意义都很明确简单函数(代码不超过20行),也可以使用单行函数头:
///函数实现功能
函数原型
{
//...
}
函数定义和其它代码之间至少分开1行空行
MFC类库使用者,返回值类型和函数名称可以写在一行。
存储类
"extern","static","inline"
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ZN22 软件编码规范指南CC+ 软件 编码 规范 指南 CC