1 排版
¹ 1-1:程序块要采用缩进风格编写,缩进的空格数为4个。
说明:对于由开发工具自动生成的代码可以有不一致。 ¹ 1-2:相对独立的程序块之间、变量说明之后必须加空行。
示例:如下例子不符合规范。 if (!valid_ni(ni)) {
... epssn_index;
repssn_ni = ssn_data[index].ni;
应如下书写 if (!valid_ni(ni)) {
... epssn_index;
repssn_ni = ssn_data[index].ni;
¹ 1-3:较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。
示例:
= NO7_TO_STAT_PERM_COUNT_LEN
+ STAT_SIZE_PER_FRAM * sizeof( _UL );
act_task_table[frame_id * STAT_TASK_CHECK_NUMBER + index].occupied
1 仅供内部使用 1
= 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));2 仅供内部使用
2
¹ 1-4:循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首。
示例:
if ((taskno < max_act_task_number)
&& (n7stat_stat_item_valid (stat_item))) {
... ord_length)
&& (j < ; i++, j++) {
... . tat_object),
sizeof (_STAT_OBJECT));
n7stat_flash_act_duration( stat_item, frame_id *STAT_TASK_CHECK_NUMBER + index, stat_object );
¹ 1-6:不允许把多个短语句写在一行中,即一行只写一条语句。
示例:如下例子不符合规范。 = 0; = 0;
应如下书写 = 0; = 0;
¹ 1-7:if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要加括号{}。
示例:如下例子不符合规范。 if (pUserCR == NULL) return;
应如下书写: if (pUserCR == NULL)
3 仅供内部使用 3
{
return; }
¹ 1-8:对齐只使用空格键,不使用TAB键。
说明:以免用不同的编辑器阅读程序时,因TAB键所设置的空格数目不同而造成程序布局不整齐,不要使用BC作为编辑器合版本,因为BC会自动将8个空格变为一个TAB键,因此使用BC合入的版本大多会将缩进变乱。
¹ 1-9:函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格,case语句下的情况处理语句也要遵从语句缩进要求。
¹ 1-10:程序块的分界符(如C/C++语言的大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。
示例:如下例子不符合规范。 for (...) { ... .) { ... . .) {
... .) {
... . 前后不加空格。
¹ p->id = pid; 文件、.inc文件、.def文件、编译说明文件.cfg等)头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者、内容、功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明。
示例:下面这段头文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。
/*************************************************
4 仅供内部使用 4
Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. File name: .... History: Date: Author: Modification: 2. ...
*************************************************/
¹ 2-3:源文件头部应进行注释,列出:版权说明、版本号、生成日期、作者、模块目的/功能、主要函数及其功能、修改日志等。
示例:下面这段源文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。
/************************************************************ Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. FileName:
Author: Version : Date: Description: -------
History: 96/10/12epssn_index; repssn_ni = ssn_data[index].ni; 例2:
repssn_ind = ssn_data[index].repssn_index; repssn_ni = ssn_data[index].ni;
/* get replicate sub system index and net indicator */
应如下书写
/* get replicate sub system index and net indicator */ repssn_ind = ssn_data[index].repssn_index; repssn_ni = ssn_data[index].ni;
5 仅供内部使用 5
¹ 2-9:对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其物理含义。变量、常量、宏的注释应放在其上方相邻位置或右方。
示例:
/* active statistic task number */ #define MAX_ACT_TASK_NUMBER 1000
#define MAX_ACT_TASK_NUMBER 1000 /* active statistic task number */
¹ 2-10:数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释放在此域的右方。
示例:可按如下形式说明枚举/数据/联合结构。
/* 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 network can not */ /* transmission this message */
N_UNITDATA_REQ, /* sccp user's unit data transmission request*/ };
¹ 2-11:全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明。
示例:
/* The ErrorCode when SCCP translate */ /* Global Title failure, as follows */ .) { ... break; }
6 仅供内部使用 6
else {
ProcessCFW_B(); .
½ 2-1:避免在一行代码或表达式的中间插入注释。
说明:除非必要,不应在代码或表达中间插入注释,否则容易使代码可理解性变差。 ½ 2-2:通过对函数或过程、变量、结构等正确的命名以及合理地组织代码的结构,使代码成为自注释的。
说明:清晰准确的函数、变量等的命名,可增加代码可读性,并减少不必要的注释。 ½ 2-3:在代码的功能、意图层次上进行注释,提供有用、额外的信息。
说明:注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。 示例:如下注释意义不大。 /* if receive_flag is TRUE */ if (receive_flag)
而如下的注释则给出了额外有用的信息。 /* if mtp receive a message from links */ if (receive_flag)
½ 2-4:在程序块的结束行右方加注释标记,以表明某程序块的结束。
说明:当代码段较长,特别是多重嵌套时,这样做可以使代码更清晰,更便于阅读。 示例:参见如下例子。 if (...) {
¹ .)*/ .),建议除了要有具体含义外,还能表明其变量类型、数据类型等,但i、j、k作局部循环变量是允许的。
说明:变量,尤其是局部变量,如果用单个字符表示,很容易敲错(如i写成j),而编译
7 仅供内部使用 7
时又检查不出来,有可能为了这个小小的错误而花费大量的查错时间。 示例:下面所示的局部变量名的定义方法可以借鉴。 int liv_Width 其变量名解释如下:
l 局部变量(Local) (其它:g 全局变量(Global)...) i 数据类型(Interger)
v 变量(Variable) (其它:c 常量(Const)...) Width 变量含义
这样可以防止局部变量与全局变量重名。
¹ 3-5:命名规范必须与所使用的系统风格保持一致,并在同一项目中统一,比如采用UNIX的全小写加下划线的风格或大小写混排的方式,不要使用大小写与下划线混排的方式,用作特殊标识如标识成员变量或全局变量的m_和g_,其后加上大小写混排的方式是允许的。
示例: Add_User不允许,add_user、AddUser、m_AddUser允许。 ½ 3-1:除非必要,不要用数字或较奇怪的字符来定义标识符。
示例:如下命名,使人产生疑惑。 #define _EXAMPLE_0_TEST_ #define _EXAMPLE_1_TEST_ void set_sls00( BYTE sls );
应改为有意义的单词命名 #define _EXAMPLE_UNIT_TEST_ #define _EXAMPLE_ASSERT_TEST_ void set_udt_msg_sls( BYTE sls );
½ 3-2:在同一软件产品内,应规划好接口部分标识符(变量、结构、函数及常量)的命名,防止编译、链接时产生冲突。
说明:对接口部分的标识符应该有更严格限制,防止冲突。如可规定接口部分的变量与常量之前加上“模块”标识等。
8 仅供内部使用 8
½ 3-3:用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。
说明:下面是一些在软件中常用的反义词组。
add / remove begin / end create / destroy insert / delete first / last get / release increment / decrement put / get add / delete lock / unlock open / close min / max old / new start / stop next / previous source / target show / hide send / receive source / destination cut / paste up / down 示例: int min_sum; int max_sum;
int add_user( BYTE *user_name ); int delete_user( BYTE *user_name );
½ 3-4:除了编译开关/头文件等特殊应用,应避免使用_EXAMPLE_TEST_之类以下划线开始和结尾的定义。
9 仅供内部使用 9
4 可读性
¹ 4-1:注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级。
说明:防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。 示例:下列语句中的表达式 word = (high << 8) | low (1) if ((a | b) && (a & c)) (2) if ((a | b) < (c & d)) (3) 如果书写为 high << 8 | low a | b && a & c a | b < c & d 由于
high << 8 | low = ( high << 8) | low, a | b && a & c = (a | b) && (a & c), (1)(2)不会出错,但语句不易理解;
a | b < c & d = a | (b < c) & d,(3)造成了判断条件出错。
¹ 4-2:避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的枚举或宏来代替。
示例:如下的程序可读性差。 if (Trunk[index].trunk_state == 0) {
Trunk[index].trunk_state = 1; ... runk_state == TRUNK_IDLE) {
Trunk[index].trunk_state = TRUNK_BUSY;
仅供内部使用
10
... 2008-9-9. . (从低到高,以字节为单位) exam exam低字节 exam高字节
内存: 0 bit 1 bit 2 bit ... (字节的各“位”) EXAM_BIT A1 A2 A3
如下是68360 CPU生成短整数及位域的方式。
内存: 0 1 2 ... (从低到高,以字节为单位) exam exam高字节 exam低字节
内存: 7 bit 6 bit 5 bit ... (字节的各“位”) EXAM_BIT A1 A2 A3
说明:在对齐方式下,CPU的运行效率要快得多。
示例:如下图,当一个long型数(如图中long1)在内存中的位置正好与内存的字边界对齐时,CPU存取这个数只需访问一次内存,而当一个long型数(如图中的long2)在内存中的位置跨越了字边界时,CPU存取这个数就需要多次访问内存,如i960cx访问这样的数需读内存三次(一个BYTE、一个SHORT、一个BYTE,由CPU的微代码执行,对软件透明),所有对齐方式下CPU的运行效率明显快多了。
1 8 16 24 32 ------- ------- ------- ------- | long1 | long1 | long1 | long1 | ------- ------- ------- ------- | | | | long2 | ------- ------- ------- -------- | long2 | long2 | long2 | | ------- ------- ------- -------- | ....
仅供内部使用
11
6 函数、过程
¹ 6-1:对所调用函数的错误返回码要仔细、全面地处理。 ¹ 6-2:明确函数功能,精确(而不是近似)地实现函数设计。
¹ 6-3:编写可重入函数时,应注意局部变量的使用(如编写C/C++语言的可重入函数时,应使用auto即缺省态局部变量或寄存器变量)。
说明:编写C/C++语言的可重入函数时,不应使用static局部变量,否则必须经过特殊处理,才能使函数具有可重入性。
¹ 6-4:编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作)等手段对其加以保护。
说明:若对所使用的全局变量不加以保护,则此函数就不具有可重入性,即当多个进程调用此函数时,很有可能使有关全局变量变为不可知状态。
示例:假设Exam是int型全局变量,函数Squre_Exam返回Exam平方值。那么如下函数不具有可重入性。
unsigned int example( int para ) {
unsigned int temp;
Exam = para; . . . . . yDataPtr, 则可以通过以下宏定义来代替:
# define pSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr
仅供内部使用
12
7 可测性
¹ 7-1:在同一项目组或产品组内,要有一套统一的为集成测试与系统联调准备的调测开关及相应打印函数,并且要有详细的说明。
说明:本规则是针对项目组或产品组的。
¹ 7-2:在同一项目组或产品组内,调测打印出的信息串的格式要有统一的形式。信息串中至少要有所在模块名(或源文件名)及行号。
说明:统一的调测信息格式便于集成测试。
¹ 7-3:编程的同时要为单元测试选择恰当的测试点,并仔细构造测试代码、测试用例,同时给出明确的注释说明。测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过调测开关)。
说明:为单元测试而准备。
¹ 7-4:在进行集成测试/系统联调之前,要构造好测试环境、测试项目及测试用例,同时仔细分析并优化测试用例,以提高测试效率。
说明:好的测试用例应尽可能模拟出程序所遇到的边界值、各种复杂环境及一些极端情况等。
¹ 7-5:使用断言来发现软件问题,提高代码可测性。
说明:断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告),它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。实际应用时,可根据具体情况灵活地设计断言。 示例:下面是C语言中的一个断言,用宏来设计的。(其中NULL为0L) #ifdef _EXAM_ASSERT_TEST_ . . . . .
indindind++indindindind++indindindind++indindength;
仅供内部使用
13
rect_width_sum += rect[ind].width; } }
因为判断语句与循环变量无关,故可如下改进,以减少判断次数。 if (data_type == RECT_AREA) {
for (ind = 0; ind < MAX_RECT_NUMBER; ind++) {
area_sum += rect_area[ind]; } } else {
for (ind = 0; ind < MAX_RECT_NUMBER; ind++) {
rect_length_sum += rect[ind].length; rect_width_sum += rect[ind].width; } }
½ 8-11:尽量用乘法或其它方法代替除法,特别是浮点运算中的除法。
说明:浮点运算除法要占用较多CPU资源。 示例:如下表达式运算可能要占较多CPU资源。 #define PAI
radius = circle_length / (2 * PAI);
仅供内部使用
14
应如下把浮点除法改为浮点乘法。 #define PAI_RECIPROCAL (1 / ) . /* global title length error */ if (gt_len > MAX_GT_LENGTH) {
return GT_LENGTH_ERROR; . . /* global title length error */ if (gt_len > MAX_GT_LENGTH) {
free( gt_buf ); . . . ); } } }
... . . . . , rect[index].b ); }
¹ 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。
仅供内部使用
15
仅供内部使用 16
_
因篇幅问题不能全部显示,请点此查看更多更全内容