【c++】编码规范及相应的配置方法

来源:互联网 发布:ppt 触发器 mac 设置 编辑:程序博客网 时间:2024/06/06 19:52

编程规范来源:腾讯 GL/YF 014-2007V1.0-L1

程序的板式

1、程序块要采用缩进风格编写,缩进的空格数为4个。

由开发工具自动生成的代码可能不一致,但如果开发工具可以配置,则应该统一配置缩进为4个空格。

配置方法:在菜单中选择: 工具-->选项-->文本编辑器--->所有语言-->制表符 在窗口中选择,制表符大小选为4,勾

选插入空格。

2、缩进或者对其只能使用空格键,不可使用TAB键。

3、相对独立的程序块之间、变量说明之后必须加空行。

以下情况应该是用空行分开:

1)函数之间应该用空行分开; 
2)变量声明应尽可能靠近第一次使用处,避免一次性声明一组没有马上使用的变量; 
3)用空行将代码按照逻辑片断划分;
4)每个类声明之后应该加入空格同其他代码分开。

示例:

if (!valid_ni(ni)) {     ... // program code } repssn_ind = ssn_data[index].repssn_index; repssn_ni  = ssn_data[index].ni; 

 

4、较长的语句(>80字符)要分成多行书写。

1)长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行
要进行适当的缩进,使排版整齐,语句可读。
2)若函数或过程中的参数较长,则要进行适当的划分。
3)循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式
要在低优先级操作符处划分新行,操作符放在新行之首。

示例:

perm_count_msg.head.len = NO7_TO_STAT_PERM_COUNT_LEN                           + STAT_SIZE_PER_FRAM * sizeof( _UL );  act_task_table[frame_id * STAT_TASK_CHECK_NUMBER + index].occupied               = stat_poi[index].occupied;  act_task_table[taskno].duration_true_or_false               = SYS_get_sccp_statistic_state( stat_item );  report_or_not_flag = ((taskno < MAX_ACT_TASK_NUMBER)                       && (n7stat_stat_item_valid (stat_item)) && (act_task_table[taskno].result_data != 0)); n7stat_str_compare((BYTE *) & stat_object,                    (BYTE *) & (act_task_table[taskno].stat_object),                    sizeof (_STAT_OBJECT));  n7stat_flash_act_duration( stat_item, frame_id *STAT_TASK_CHECK_NUMBER                                    + index, stat_object );  if ((taskno < max_act_task_number)     && (n7stat_stat_item_valid (stat_item))) {     ... // program code }  for (i = 0, j = 0; (i < BufferKeyword[word_index].word_length)                     && (j < NewKeyword.word_length); i++, j++) {     ... // program code }  for (i = 0, j = 0;        (i < first_word_length) && (j < second_word_length);   `     i++, j++) {     ... // program code  } 

5、不允许把多个短语句写在一行中,即一行只写一条语句。

一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。

6、if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要加括号{}。

示例:

如下例子不符合规范:

if (pUserCR == NULL) return; 

应如下书写:

if (pUserCR == NULL) {     return; } 

7、代码行之内应该留有适当的空格

采用这种松散方式编写代码的目的是使代码更加清晰。代码行内应该适当的使用空格。

具体如下:

1)关键字之后要留空格。像const、virtual、inline、case   等关键字之后至少要留一个空格,否则无法辨析关键字。if、for、while   等关键字之后应留一个空格再跟左括号‘( ’, 以突出关键字。 
2)函数名之后不要留空格, 紧跟左括号’(’  , 以与关键字区别。 
3)‘( ’ 向后紧跟,‘ )’、‘ ,’、‘ ;’ 向前紧跟, 紧跟处不留空格。 
4)‘ ,’ 之后要留空格, 如Function(x, y, z)。如果‘ ;’ 不是一行的结束符号, 其
后也要留空格, 如for  (initialization;  condition; update)。 
5)值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“ =”、“ +=”   “ >=”、“ <=”、“ +”、“ *”、“ %”、“ &&”、“ ||”、“ <<” 、“ ^” 等二元操作符的前后应当加空格。 
6)一元操作符如“ !”、“ ~”、“ ++”、“ --”、“ &”( 地址运算符) 等前后不加空格。 
7)“[ ]”、“ .”、“ ->” 这类操作符前后不加空格。
示例:

void foo() { …// program code }    if (i == 0) { …// program code }   foo->bar, foo.bar, foo[bar]  i++, !i, &i  i += 9, a * b 

8、程序块的分界符(如'{'和'}')应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。

示例:

如下例子不符合规范:

for (...) {     ... // program code }  if (...)      {     ... // program code     }  void example_fun( void )     {     ... // program code     } 

应如下书写:

for (...)  {     ... // program code }  if (...)  {     ... // program code }  void example_fun( void ) {     ... // program code } 

注释

9、源文件头部应进行注释,列出;生成日期、作者、模块目的/功能等。

示例:

/************************************************************   FileName: test.cpp   Author:        Version :          Date:   Description:     // 模块描述         Version:         // 版本信息   Function List:   // 主要函数及其功能     1. -------   History:         // 历史修改记录       <author>  <time>   <version >   <desc>       David    96/10/12     1.0     build this moudle   ***********************************************************/ 

10、函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值等。
示例:

/*************************************************   Description:    // 函数功能、性能等的描述   Input:          // 输入参数说明,包括每个参数的作                   // 用、取值说明及参数间关系。   Output:         // 对输出参数的说明。   Return:         // 函数返回值的说明   Others:         // 其它说明 *************************************************/ 

右击函数名,然后依次点击“Refacto”–>“Document Method”。

但是这个注释格式是默认的,可能不适合你的项目。可以在VAssistX的选项中更改显示样式,在VS2008中点击 “VAssistX”–>”Visual VAssistX Options”然后选择Suggestions,再点击”Edit VA Snippets”。在打开的窗口中选择Refactor -> Document Method,在这就可以更改你的显示样式了。
例如:
//************************************// Description: // Method:    $SymbolName$// FullName:  $SymbolContext$// Access:    $SymbolVirtual$$SymbolPrivileges$$SymbolStatic$// Parameter: $MethodArg$// Returns:   $SymbolType$// Author:    xxx// Date:      $DATE$// History://************************************

11、注释应该和代码同时更新,不再有用的注释要删除。

12、注释的内容要清楚、明了、不能有二义性。

13、避免在注释中使用非常用的缩写或者术语。

14、注释的主要目的应该是解释为什么这样做,而不是正在做什么。如果从上下文不容易看出作者的目的,说明程序的可读性本身存在比较大的问题。

15、避免非必要的注释。

例如:

ClassA *pA = new ClassA();//创建新实例     … …… …      delete pA;  //销毁对象
16、注释的板式

说明:注释也需要与代码一样整齐排版

1)注释应与其描述的代码相近,对代码的注释应放在其上方或右方相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。

2)注释与所描述内容进行同样的缩排。

3)将注释与其上面的代码用空行隔开。

4)变量、常量、宏的注释应放在其上方相邻位置或右方。

示例:如下例子不符合规范。

注释在代码行之下:

repssn_ind = ssn_data[index].repssn_index; repssn_ni = ssn_data[index].ni; /* get replicate sub system index and net indicator */
缩进不统一:

void example_fun( void ) { /* code one comments */     CodeBlock One          /* code two comments */     CodeBlock Two } 
代码过于紧凑:

/* code one comments */ program code one /* code two comments */ program code two 
17、对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其物理含义。

示例:以下都是允许的注释方式

/* active statistic task number */ #define MAX_ACT_TASK_NUMBER 1000  #define MAX_ACT_TASK_NUMBER 1000 /* active statistic task number */ 
18、数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释可放在此域的右方。

示例:

/* sccp interface with sccp user primitive message name */ enum  SCCP_USER_PRIMITIVE {     N_UNITDATA_IND, /* sccp notify sccp user unit data come */     N_NOTICE_IND,   /* sccp notify user the No.7 network can not */                     /* transmission this message */     N_UNITDATA_REQ, /* sccp user's unit data transmission request*/ }; 
19、对重要变量的定义需编写注释,特别是全局变量。,更应有较详细的注释,包括对其功能、取值范围、以及存取时注意事项等说明。

示例:

/* The ErrorCode when SCCP translate   Global Title failure, as follows       // 变量作用、含义  0 - SUCCESS   1 - GT Table error   2 - GT error  Others - not in use         // 变量取值范围  only  function  SCCPTranslate() in   this module can modify it,  and  other   module can visit it through call   the  function GetGTTransErrorCode() */    // 使用方法 BYTE g_GTTranErrorCode;   
20、分支语句(条件分支、循环语句等)需编写注释。

21、注释不宜过多,也不能太少,源程序中有效注释量控制在20%~30%之间。

标识符命名

22、命名尽量使用英文单词,力求简单清楚,避免使用引起误会的词汇和模糊的缩写,使人产生误解。

较短的单词可通过去掉“元音”形成缩写;较长的单词可取单词的头几个字母形成缩
写;一些单词有大家公认的缩写。 
示例:如下单词的缩写能够被大家基本认可

temp 可缩写为  tmp  ; 
flag 可缩写为  flg  ; 
statistic 可缩写为  stat ; 
increment 可缩写为  inc  ; 
message 可缩写为  msg  ; 

23、命名规范必须与所使用的系统风格保持一致,并在同一项目中统一。

说明: 
1)如在 UNIX系统,可采用全小写加下划线的风格或大小写混排的方式,但不能使用大小写与下划线混排的方式。 
2)用作特殊标识如标识成员变量或全局变量的 m_和g_,其后加上大小写混排的方式是允许的。 
示例:

Add_User不允许,add_user、AddUser、m_AddUser允许。

24、变量的命名可参考“匈牙利”标记法。

例外:

c++程序不建议采用匈牙利命名法。因为c++本身就是强类型语言,不需要像c一样用匈牙利命名法来强调变量类型。

有两个匈牙利命名法可以保留:m_xxxx表示类的成员变量,g_xxx表示全局变量。

25、常量、宏和模版名采用全大写的方式,每个单词间用下划线分割。

26、枚举类型enum常量应以大写字母开头或全部大写。

27、命名中若使用了特殊约定或缩写,则要有注释说明。

28、对于变量命名,禁止取单个字符(如i,j,k。。),建议除了要有具体含义外,还能表明其变量类型、数据类型等,但i,j,k作局部循环变量是允许的。

说明:变量,尤其是局部变量,如果用单个字符表示,很容易敲错,而编译时又检查不出来,有可能为了这个小小的错误而花费大量的查错时间。

29、函数名以大写字母开头,采用谓-宾结构(动-名),且反映函数执行什么操作以及返回什么内容。

说明: 
函数在表达式中使用,通常用于 if  子句,因此它们的意图应一目了然。 
示例: 
不好的命名:if (CheckSize(x))  
没有帮助作用,因为它没有告诉我们 CheckSize 是在出错时返回 true  还是在不出错时返回 true。 
好的命名:if (ValidSize(x)) 
则使函数的意图很明确。 

30、类、结构、联合、枚举的命名须分别以C、S、U、E开头。


可读性

31、用括号明确表达式的操作顺序,避免使用默认优先级。

说明:防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。

32、不要编写太复杂、多用途的符合表达式。

33、涉及物理状态或者含有物理意义的常量,避免直接使用数字,必须用有意义的枚举或者常量来代替。

示例:

如下例子可读性差:

if (Trunk[index].trunk_state == 0) {     Trunk[index].trunk_state = 1;     ...  // program code } 
应改为如下形式:

const int TRUNK_IDLE = 0; const int TRUNK_BUSY = 1;  if (Trunk[index].trunk_state == TRUNK_IDLE) {     Trunk[index].trunk_state = TRUNK_BUSY;     ...  // program code } 
34、禁止使用难以理解,容易产生歧义的语句。
示例:

如下表达式难以理解:

* stat_poi ++ += 1;  * ++ stat_poi += 1; 
应分别改为如下:

*stat_poi += 1; stat_poi++;     // 此二语句功能相当于“ * stat_poi ++ += 1; ”  ++ stat_poi; *stat_poi += 1; // 此二语句功能相当于“ * ++ stat_poi += 1; ” 


变量、结构

35、尽量少使用全局变量,尽量去掉没必要的公共变量。

说明:公共变量是增大模块间耦合的原因之一,故应减少没必要的公共变量以降低模块间的耦合度。 

36、变量,特别是指针变量,被创建之后应当及时把它们初始化,以防止未被初始化的变量当成右值使用。

说明:在c/c++中引用未经赋值的指针,经常会引起系统崩溃。

37、仔细设计结构中元素的布局与排列顺序,使结构容易理解、节省占用空间,并减少引用误用现象。
38、留心具体语言及编译器处理不同数据类型的原则及有关细节。

说明:如在C语言中,static局部变量将在内存“数据区”中生成,而非static局部变量将在“堆栈”中生成。这些细节对程序质量的保证非常重要。

39、尽量减少没有必要的数据类型默认转换与强制转换。

说明:当进行数据类型强制转换时,其数据的意义、转换后的取值等都有可能发生变化,而这些细节若考虑不周,就很有可能留下隐患。

40、当声明用于分布式环境或不同CPU间通信环境的数据结构时,必须考虑机器的字节顺序、使用的位域及字节对其等问题。

说明:

1)在intel CPU与SPARC CPU,在处理位域及整数时,其在内存存放的“顺序”正好相反。

2)在对齐方式下,CPU的运行效率要快一些。

函数、过程 

41、调用函数要检查所有可能的返回情况,不应该的返回情况要用ASSERT来确认。

42、编写可重入函数时,应注意局部变量的使用。(……)

43、调用公共接口函数时,调用者有保障调用参数符合要求的义务。作为一种防御性的编程风格,被调用函数也应该对传入参数做必须的安全检查。

44、函数的规模尽量限制在100行以内。不包括注释和空行。

45、不能用AEESET代替必要的安全处理代码,确保发布版的程序也能够合理地处理异常情况。

例如:

void Reset(int *p) {  assert(NULL != p);  if(NULL != p)  //不能因为前面的assert,省略此处的判断 {  *p = 0; } } 
46、尽量写类的构造、拷贝构造、析构和赋值函数,而不使用系统缺省的。(……)

47、检查函数所有参数与非参数的有效性。

说明: 
1)函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入,即非参数输入。函数在使用输入之前,应进行必要的检查。 
2)不应该的入口情况要用ASSERT 来确认。 
3)有时候不处理也是一种处理,但要明确哪些情况不处理。try...catch 是一种常用的不处理的处理手段。 

48、函数实现中不改变内容的参数要定义成const。

示例:

int GetStrLen(const char*);  int GetNumberCount(const CString&); 
49、函数的返回值要清楚、明了,让使用者不容易忽视错误情况。
说明: 
函数的每种出错返回值的意义要清晰、明了、准确,防止使用者误用、理解错误或忽视错误返回码。 


 C++专用规范

 50、在高警告级别下干净地编译。

使用编译器的最高警告级别。要求干净的(没有警告的)构建(build)并理解所有的警告。通过修改代码来消除警告,而不是通过降低警告级别来消除。对于明确理解其
含义,确信不会造成任何问题的警告,则可以局部关闭。

51、主动使用const,避免使用宏。

应该尽可能的使用常量而不用变量,另外在定义数值的时候,应该把 const 做为默认的选项。它是安全的,在编译的时候(参见附录C《编码安全规范》)检查,它集成在
C++的类型系统中。除非要调用一个非const 函数,否则不要强制去除const。 宏无视作用域,无视类型系统,无视所有其它的语言特性和规则,并从#define 处开始将该符号劫持。只有对少数的重要任务,宏仍是仅有的解决方案,如#include 防护哨,用于条件编译的#ifdef 和#if defined,以及用来实现assert。

52、合理使用组合和继承。

继承是C++中耦合度最强的关系之一。软件工程的一条重要原则是尽量减少耦合,在组合和继承都能均可适用的情况下,应该优先考虑使用组合。组合的意思是将一种类型
以成员变量方式嵌入相关类型中。组合有如下优点: 
1)在不影响调用代码的同时也更灵活。 
2)编译期绝缘性好,编译时间也能缩短。 
3)代码不可预测程度降低(有些类不适合作为基类)。

53、尽可能局部地声明变量。

尽可能局部地声明每个变量,这通常是在程序具备了足够的数据来初始化变量之后,并紧接着首次使用该变量之前。 
例外: 
1)有时将变量从循环内提出到循环外是有益的。 
2)由于常量不增加状态,因此本条对常量不适用。 

54、通过值,指针,或引用适当地取得参数。

对仅用于输入的参数来说: 
1)始终给仅用于输入的指针或引用参数加上const 限定符。  
2)最好是通过原始类型(例如:char,float)和可以通过值来复制并且复制成本低的值对象(例如:Point complex<float>)来取得参数。  
3)对其它自定义类型的输入,最好是通过const 引用来取得。  
4)如果函数需要参数的复本,那么可以考虑用传递值来代替传递引用。从概念上说,这等价于取得一个 const 引用再做一次复制,它可以帮助编译器更好地优化掉临时对象。

对输出或输入/输出参数来说: 
1)如果参数是可选的(因此调用方可以传递空指针来表示“不可用”或“不关心”的值),或者函数要保存指针的一个复本或操控参数的所有权,那么最好是通过(智能)指针传递。  
2)如果参数是必需的,而且函数无需保存指向该参数的指针或无需操控参数的所有权,那么最好是通过引用传递。这表明该参数是必需的,并让调用方来负责提供一个有效的对象。


 

0 0
原创粉丝点击