首先给出我读的《华为C++编程规范》的下载传送门:
(等待上传ing...)
说明:以下都是我把我在看规范的过程中,觉得对“我”有用的地方摘录了下来,注意,我把“我”字强调了,说明我摘录的几点你们不一定觉得好。我建议大家都看看这份编码规范(网上还有google的,也建议看看),当然,什么东西都不是绝对完美的,就像这份规范一样,大家可以选择性的吸纳,规范加个性(自己的习惯),两者结合,把握好自己平衡点,才是好的。
在这几天,我也会抽时间把google的C++编码规范做一下笔记,也希望更多的朋友一起学习,一起交流。
(交流论坛:
C++奋斗乐园:www.CppLeYuan.com
)
附:最近在公司实习(今天刚辞了),给我最大的感受就是一个代码的规范性,以前写的都是几十行的小代码,所以无法感受到,真正看了大的项目,首先连一些基本(算是约定俗成的规范吧!),我都不知道,所以才额外关注了编码的规范问题!还有很好需要学的啊。。。
---------------以下是笔记--------------
-----|排版|-----
1.对齐只使用空格键,不使用TAB键(对应原文件1.8) 说明:以免用不同的编辑器阅读程序时,因TAB键所设置的空格数目不同而造成程序布局不整齐,不要使用BC作为编辑器合版本,因为BC会自动将8个空格变为一个TAB键,因此使用BC合入的版本大多会将缩进变乱。 (个人说明:这个以前没有注意,那天在公司,header首先给我的VS2008改了几个选项,就包括这个,当然有点不明白,现在懂了)
2.在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,如果是关系密切的立即操作符(如->),后不应加空格。(对应1.11) 说明:采用这种松散方式编写代码的目的是使代码更加清晰。 由于留空格所产生的清晰性是相对的,所以,在已经非常清晰的语句中没有必要再留空格,如果语句已足够清晰则括号内侧(即左括号后面和右括号前面)不需要加空格,多重括号间不必加空格,因为在C/C++语言中括号已经是最清晰的标志了。 在长语句中,如果需要加的空格非常多,那么应该保持整体清晰,而在局部不加空格。给操作符留空格时不要连续留两个以上空格。
示例:
(1) 逗号、分号只在后面加空格。
int a, b, c;
(2)比较操作符, 赋值操作符"="、 "+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位域操作符"<<"、"^"等双目操作符的前后加空格。
if (current_time >= MAX_TIME_VALUE)
a = b + c;
a *= 2;
a = b ^ 2;
(3)"!"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。
*p = 'a'; // 内容操作"*"与内容之间
flag = !isEmpty; // 非操作"!"与内容之间
p = &mem; // 地址操作"&" 与内容之间
i++; // "++","--"与内容之间
(4)"->"、"."前后不加空格。
p->id = pid; // "->"指针前后不加空格
(5) if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。
if (a >= b && c > d)
-----|注释|-----
3.一般情况下,源程序有效注释量必须在20%以上。(对应2.1) 说明:注释的原则是有助于对程序的阅读理解,在该加的地方都加了,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。
4.说明性文件(如头文件.h文件、.inc文件、.def文件、编译说明文件.cfg等)头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者、内容、功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明。(对应2.2)
示例:下面这段头文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。
/*************************************************
Copyright (C), 1988-1999, Huawei Tech. Co., Ltd.
File name: // 文件名
Author: Version: Date: // 作者、版本及完成日期
Description: // 用于详细说明此程序文件完成的主要功能,与其他模块
// 或函数的接口,输出值、取值范围、含义及参数间的控
// 制、顺序、独立或依赖等关系
Others: // 其它内容的说明
Function List: // 主要函数列表,每条记录应包括函数名及功能简要说明
1. ....
History: // 修改历史记录列表,每条修改记录应包括修改日期、修改
// 者及修改内容简述
1. Date:
Author:
Modification:
2. ...
*************************************************/
5.源文件头部应进行注释,列出:版权说明、版本号、生成日期、作者、模块目的/功能、主要函数及其功能、修改日志等。(对应2.3)
示例:下面这段源文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。
/************************************************************
Copyright (C), 1988-1999, Huawei Tech. Co., Ltd.
FileName: test.cpp
Author: Version : Date:
Description: // 模块描述
Version: // 版本信息
Function List: // 主要函数及其功能
1. -------
History: // 历史修改记录
David 96/10/12 1.0 build this moudle
***********************************************************/
说明:Description一项描述本文件的内容、功能、内部各部分之间的关系及本文件与其它文件关系等。History是修改历史记录列表,每条修改记录应包括修改日期、修改者及修改内容简述。
6.函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)等。(对应2.4)
示例:下面这段函数的注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。
/*************************************************
Function: // 函数名称
Description: // 函数功能、性能等的描述
Calls: // 被本函数调用的函数清单
Called By: // 调用本函数的函数清单
Table Accessed: // 被访问的表(此项仅对于牵扯到数据库操作的程序)
Table Updated: // 被修改的表(此项仅对于牵扯到数据库操作的程序)
Input: // 输入参数说明,包括每个参数的作
// 用、取值说明及参数间关系。
Output: // 对输出参数的说明。
Return: // 函数返回值的说明
Others: // 其它说明
*************************************************/
7.在程序块的结束行右方加注释标记,以表明某程序块的结束。(对应2.19) 说明:当代码段较长,特别是多重嵌套时,这样做可以使代码更清晰,更便于阅读。
示例:参见如下例子。
if (...)
{
// program code
while (index < MAX_INDEX)
{
// program code
} /* end of while (index < MAX_INDEX) */ // 指明该条while语句结束
} /* end of if (...)*/ // 指明是哪条if语句结束
-----|标识符命名|-----
8.除了编译开关/头文件等特殊应用,应避免使用EXAMPLETEST_之类以下划线开始和结尾的定义。(对应3.9)
-----|变量,结构|------
9.去掉没必要的公共变量。(对应5.1)
说明:公共变量是增大模块间耦合的原因之一,故应减少没必要的公共变量以降低模块间的耦合度。
10.不要设计面面俱到、非常灵活的数据结构。(对应5-4)
说明:面面俱到、灵活的数据结构反而容易引起误解和操作困难。
(个人理解,这个也是片面的,关键还是在于开发者把握好尺度的问题)
11.留心具体语言及编译器处理不同数据类型的原则及有关细节。(对应5.9)
说明:如在C语言中,static局部变量将在内存“数据区”中生成,而非static局部变量将在“堆栈”中生成。这些细节对程序质量的保证非常重要。
-----|函数,过程|-----
12.编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作)等手段对其加以保护。(对应6.4) 说明:若对所使用的全局变量不加以保护,则此函数就不具有可重入性,即当多个进程调用此函数时,很有可能使有关全局变量变为不可知状态。
13.为简单功能编写函数。(对用6.4) 说明:虽然为仅用一两行就可完成的功能去编函数好象没有必要,但用函数可使功能明确化,增加程序可读性,亦可方便维护、测试。
示例:如下语句的功能不很明显。
value = ( a >; b ) ? a : b ;
改为如下就很清晰了。
int max (int a, int b)
{
return ((a > b) ? a : b);
}
value = max (a, b);
或改为如下。
#define MAX (a, b) (((a) > (b)) ? (a) : (b))
value = MAX (a, b);
(个人理解:#define这个不太推荐,放着好好的函数不用,何必徒增烦恼?)
-----|可测性|-----
14.使用断言来发现软件问题,提高代码可测性。(对应7.5) 说明:断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告),它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。实际应用时,可根据具体情况灵活地设计断言。
15.用断言确认函数的参数。(对应7.9)
示例:假设某函数参数中有一个指针,那么使用指针前可对它检查,如下。
int exam_fun( unsigned char *str )
{
EXAM_ASSERT( str != NULL ); // 用断言检查“假设指针不为空”这个条件
... //other program code
16.使用代码检查工具(如C语言用PC-Lint)对源程序检查。 使用软件工具(如 LogiSCOPE)进行代码审查。
(以上两个我也没用过,这几天研究下)
-----|宏|-----
17.将宏所定义的多条表达式放在大括号中。(对应13.2)
示例:下面的语句只有宏的第一条表达式被执行。为了说明问题,for语句的书写稍不符规范。
#define INTI_RECT_VALUE( a, b )\
a = 0;\
b = 0;
for (index = 0; index < RECT_TOTAL_NUM; index++)
INTI_RECT_VALUE( rect.a, rect.b );
正确的用法应为:
#define INTI_RECT_VALUE( a, b )\
{\
a = 0;\
b = 0;\
}
for (index = 0; index < RECT_TOTAL_NUM; index++)
{
INTI_RECT_VALUE( rect[index].a, rect[index].b );
}
19:使用宏时,不允许参数发生变化。(对应12.3)
示例:如下用法可能导致错误。
#define SQUARE( a ) ((a) * (a))
int a = 5;
int b;
b = SQUARE( a++ ); // 结果:a = 7,即执行了两次增1。
正确的用法是:
b = SQUARE( a );
a++; // 结果:a = 6,即只执行了一次增1。