当前位置:首页 >> 信息与通信 >>

2.6 C语言编程规范


嵌入式C\C++程序设计
大连理工大学软件学院 嵌入式教研室 赖晓晨

软件开发编码规范
广州HW有限公司质量管理体系文件

引言
为了提高源程序的质量和可维护性,最终提 高公司软件产品生产力,我们有必要对公司 软件产品的源程序的编写风格作出统一的规 范约束。本文档的读者是系统分析设计人员 和C\C++程序

代码编制人员、测试人员。

总则
本规范总则的内容包括:
排版 注释 标识符命名 变量使用 代码可测性 程序效率 质量保证 代码编译 单元测试 程序版本与维护

术语:
术语描述:
规则:编程时强制必须遵守的原则。 建议:编程时必须加以考虑的原则。 说明:对此规则或建议进行必要的解释。 示例:对此规则或建议从正、反两个方面 给出例子。

1。排版
1-1: 程序块要采用缩进风格编写,缩进的 空格数为4个。
说明:对于由开发工具自动生成的代码可以有 不一致。

1。排版(续)
1-2:相对独立的程序块之间、变量说明之 后必须加空行。
示例:如下例子不符合规范。 if (!valid_ni(ni)) { ... // program code } repssn_ind = ssn_data[index].repssn_index; repssn_ni = ssn_data[index].ni; 应如下书写: if (!valid_ni(ni)) { ... // program code } repssn_ind = ssn_data[index].repssn_index; repssn_ni = ssn_data[index].ni;

1。排版(续)
1-3:较长的语句(>80字符)要分成多行 书写,长表达式要在低优先级操作符处划分 新行,操作符放在新行之首,划分出的新行 要进行适当的缩进,使排版整齐,语句可 读。

1。排版(续)
示例: 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));

1。排版(续)
1-4:循环、判断等语句中若有较长的表达 式或语句,则要进行适应的划分,长表达式 要在低优先级操作符处划分新行,操作符放 在新行之首。

1。排版(续)
示例: 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 }

1。排版(续)
1-5:若函数或过程中的参数较长,则要进 行适当的划分。
示例: n7stat_str_compare((BYTE *) & stat_object, (BYTE *) & (act_task_table[taskno].stat_object), sizeof (_STAT_OBJECT));

1。排版(续)
1-6:不允许把多个短语句写在一行中,即 一行只写一条语句。
示例:如下例子不符合规范。 rect.length = 0; rect.width = 0; 应如下书写: rect.length = 0; rect.width = 0;

1。排版(续)
1-7:if、for、do、while、case、 switch、default等语句自占一行,且 if、for、do、while等语句的执行语句部 分无论多少都要加括号{}。
示例:如下例子不符合规范。 if (pUserCR == NULL) return; 应如下书写: if (pUserCR == NULL) { return; }

1。排版(续)
1-8:对齐只使用空格键,不使用TAB键。 说明:以免用不同的编辑器阅读程序时,因 TAB键所设置的空格数目不同而造成程序布 局不整齐。不要使用BC作为编辑器,因为 BC会自动将8个空格变为一个TAB键,因 此使用BC合入的版本大多会将缩进变乱。

1。排版(续)
1-9:函数或过程的开始、结构的定义及循 环、判断等语句中的代码都要采用缩进风 格,case语句下的情况处理语句也要遵从 语句缩进要求。

1。排版(续)
1-10:程序块的分界符(如C/C++语言 的大括号‘{’和‘}’)应各独占一行并且位于 同一列,同时与引用它们的语句左对齐。在 函数体的开始、类的定义、结构的定义、枚 举的定义以及if、for、do、while、 switch、case语句中的程序都要采用如上 的缩进方式。

1。排版(续)
示例:如下例子不符合规范。 for (...) { ... // program code } if (...) { ... // program code } void example_fun( void ) { ... // program code } 应如下书写。 for (...) { ... // program code } if (...) { ... // program code } void example_fun( void ) { ... // program code }

1。排版(续)
1-11:在两个以上的关键字、变量、常量进 行对等操作时,它们之间的操作符之前、之后 或者前后要加空格;进行非对等操作时,如果 是关系密切的立即操作符(如->),后不应 加空格。
说明:采用这种松散方式编写代码的目的是使代码更 加清晰。由于留空格所产生的清晰性是相对的,所 以,在已经非常清晰的语句中没有必要再留空格,如 果语句已足够清晰则括号内侧(即左括号后面和右括号 前面)不需要加空格,多重括号间不必加空格,因为在 C/C++语言中括号已经是最清晰的标志了。给操作符 留空格时不要连续留两个以上空格。

1。排版(续)
示例: (1) 逗号、分号只在后面加空格。 int a, b, c; (2)比较操作符, 赋值操作符“=”、 “+=”,算术操作符“+”、“%”, 逻辑操作符"&&"、"&",位域操作符"<<"、"^"等双目操作符的前后加空格。 if (current_time >= MAX_TIME_VALUE) a = b + c; a *= 2; a = b ^ 2;

1。排版(续)
(3)"!"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。 *p = 'a'; p = &mem; i++; p->id = pid; 更为突出、明显。 if (a >= b && c > d) // 内容操作"*"与内容之间 // 地址操作"&" 与内容之间 // "++","--"与内容之间 // "->"指针前后不加空格 flag = !isEmpty; // 非操作"!"与内容之间

(4)"->"、"."前后不加空格。 (5) if、for、while、switch等与后面的括号间应加空格,使if等关键字

1。排版(续)
建议1-1:一行程序以小于80字符为宜, 不要写得过长。 建议1-2:源文件说明采用如下次序:
头文件 宏定义 函数定义 全局变量定义

2。注释
规则2-1:一般情况下,源程序有效注释量 必须在20%以上。 说明:注释的原则是有助于对程序的阅读理 解,注释不宜太多也不能太少,注释语言必 须准确、易懂、简洁。

2。注释(续)
规则2-2:说明性文件(如头文件.h文 件、.inc文件、.def文件、配置说明文 件.cfg等)头部应进行注释,注释必须列 出:版权说明、版本号、生成日期、作者、 内容、功能、与其它文件的关系、修改日志 等,头文件的注释中还应有函数功能简要说 明。

2。注释(续)
示例:下面这段头文件的头注释比较标准,当然,并不局限于此格式,但上述信息 建议要包含在内。 /************************************************** Copyright (C), 1996-2000, Sunrise Tech. Co., Ltd. File name: // 文件名 Author: Version: Date: // 作者、版本及完成日期 Description: // 用于详细说明此程序文件完成的主要功能,与其他模块 // 或函数的接口,输出值、取值范围、含义及参数间的控 // 制、顺序、独立或依赖等关系 Others: // 其它内容的说明 Function List: // 主要函数列表,每条记录应包括函数名及功能简要说明 1. .... History: // 修改历史记录列表,每条修改记录应包括修改日期、修改 // 者及修改内容简述 1. Date: Author: Modification: 2. ... **************************************************/

2。注释(续)
规则2-3:源文件头部应进行注释,列出: 版权说明、版本号、生成日期、作者、模块 目的/功能、主要函数及其功能、修改日志 等。

2。注释(续)
示例:下段源文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议 要包含在内。 /**************************************************** FileName: test.pc Author: Version : Date: Description: // 模块描述 Version: // 版本信息 Function List: // 主要函数及其功能 1. -------History: // 历史修改记录 <author> <time> <version > <desc> David 99/10/12 1.0 build this moudle ****************************************************/ 说明:Description一项描述本文件的内容、功能、内部各部分之间的关系及本文 件与其它文件关系等。History是修改历史记录列表,每条修改记录应包括修改日期、 修改者及修改内容简述。

2。注释(续)
规则2-4:函数头部应进行注释,列出:函 数的目的/功能、输入参数、输出参数、返 回值、调用关系(函数、表)等。

2。注释(续)
示例:下面这段函数的注释比较标准,当然,并不局限于此格式,但上述信息 建议要包含在内。 /*************************************************** 函数名称: // 函数名称 函数功能描述: // 函数功能、性能等的描述 访问的表: // 被访问的表(此项仅对于牵扯到数据库操作的程序) 修改的表: // 被修改的表(此项仅对于牵扯到数据库操作的程序) 输入参数: // 输入参数说明,包括每个参数的作用、取值说明及参数间关系。 输出参数: // 对输出参数的说明。 返回值: // 函数返回值的说明 其它说明: // 其它说明 ****************************************************/

2。注释(续)
规则2-5:边写代码边注释,修改代码同时修改相 应的注释,以保证注释与代码的一致性。不再有用 的注释要删除。 规则2-6:注释的内容要清楚、明了,含义准确, 防止注释二义性。 说明:错误的注释不但无益反而有害。 规则2-7:避免在注释中使用缩写,特别是非常用 缩写。 说明:在使用缩写时或之前,应对缩写进行必要的 说明。

2。注释(续)
示例:如下例子不符合规范。 例1: /* International roamer calculate toll fee */

strcpy(deb.chargecode,CHARGE_IDD); strcpy(deb.calltype,CALLTYPE_IDD); 例2: strcpy(deb.chargecode,CHARGE_IDD); strcpy(deb.calltype,CALLTYPE_IDD); /* International roamer calculate toll fee */ 应如下书写 /* International roamer calculate toll fee */ strcpy(deb.chargecode,CHARGE_IDD); strcpy(deb.calltype,CALLTYPE_IDD);

2。注释(续)
规则2-9:对于所有有特定含义的变量、常 量,如果其命名不是充分自注释的,在声明 时都必须加以注释,说明其特定含义。变 量、常量、宏的注释应放在其上方相邻位置 或右方。
示例: /* active statistic task number */ #define MAX_ACT_TASK_NUMBER 1000 #define MAX_ACT_TASK_NUMBER 1000 /* active statistic task number */

2。注释(续)
规则2-10:数据结构声明(包括数组、结 构、类、枚举等),如果其命名不是充分自 注释的,必须加以注释。对数据结构的注释 应放在其上方相邻位置,不可放在下面;对 结构中的每个域的注释放在此域的右方。

2。注释(续)
示例:可按如下形式说明枚举/数据/联合结构。 /* structure definition for parameter request item*/ typedef struct { char *name; int type; void *value; int need; int size; int *number; int nummax; } Para, *pPara; /* parameter name */ /* data type */ /* variable to store parameter value */ /* needful */ /* variable size */ /* variable to store parameter count */ /* arrary size */

2。注释(续)
规则2-11:注释与所描述内容进行同样的 缩排。 说明:可使程序排版整齐,并方便注释的阅 读与理解。

2。注释(续)
示例:如下例子,排版不整齐,阅读稍感不方便。 void example_fun( void ) { /* code one comments */ CodeBlock One /* code two comments */ CodeBlock Two } 应改为如下布局。 void example_fun( void ) { /* code one comments */ CodeBlock One /* code two comments */ CodeBlock Two }

2。注释(续)
规则2-12:将注释与其上面的代码用空行 隔开。 示例:如下例子,显得代码过于紧凑。
/* code one comments */ program code one /* code two comments */ program code two 应如下书写 /* code one comments */ program code one /* code two comments */ program code two

2。注释(续)
规则2-13:对变量的定义和分支语句(条 件分支、循环语句等)必须编写注释。 说明:这些语句往往是程序实现某一特定功 能的关键,对于维护人员来说,良好的注释 帮助更好的理解程序,有时甚至优于看设计 文档。

2。注释(续)
规则2-14:对于switch语句下的case语 句,如果因为特殊情况需要处理完一个 case后进入下一个case处理,必须在该 case语句处理完、下一个case语句前加上 明确的注释。 说明:这样比较清楚程序编写者的意图,有 效防止无故遗漏break语句。

2。注释(续)
示例(注意斜体部分): case CMD_DOWN: ProcessDown(); break; case CMD_FWD: ProcessFwd(); if (...) { ... break; } else { ProcessCFW_B(); } case CMD_A: ProcessA(); break;

// now jump into case CMD_A

2。注释(续)
建议2-1:避免在一行代码或表达式的中间 插入注释。 说明:除非必要,不应在代码或表达中间插 入注释,否则容易使代码可理解性变差。 建议2-2:通过对函数或过程、变量、结构 等正确的命名以及合理地组织代码的结构, 使代码成为自注释的。 说明:清晰准确的函数、变量等的命名,可 增加代码可读性,并减少不必要的注释。

2。注释(续)
建议2-3:在程序块的结束行右方加注释标 记,以表明某程序块的结束。 说明:当代码段较长,特别是多重嵌套时, 这样做可以使代码更清晰,更便于阅读。

2。注释(续)
示例:参见如下例子。 if (...) { // program code while (index < MAX_INDEX) { // program code } /* end of while (index < MAX_INDEX) */ // 指明该条while语句结束 } /* end of if (...)*/ // 指明是哪条if语句结束

2。注释(续)
建议2-4:注释应考虑程序易读及外观排版 的因素,使用的语言若是中、英兼有的,建 议多使用中文,除非能用非常流利准确的英 文表达。 说明:注释语言不统一,影响程序易读性和 外观排版,出于对维护人员的考虑,建议使 用中文。

3。命名规则
规则3-1:应该按照功能模块划分目录结 构。模块命名规则:模块名拼音缩写 +“_”+模块类别。如:营销执行 (YX_Opr)、帐务管理(ZW_Mag)。

3。命名规则
规则3-2:命名的前缀.
1. 函数名: 函数名必须以大写字母开 头。 2. 类名: 必须以大写“T”开头,后面 字母反映具体含义,以清晰表 达类的用途和功能为原则。 接口必须以大写"I"开头, 代表 Interface 。 3. 变量类型 [m_|gs_|g_] variable name 类的成员变量前加"m_ " 类的静态成员变量"ms_" 静态全局变量"gs_" 普通全局变量"g_"

3。命名规则
规则3-3:通用单元文件(如公共函数库、 变量库、常量库等)的命名应尽量表达它的 含义,并以lib作为前缀。 规则3-4:所有常量名统一使用大写。 规则3-5:常量名称=前缀+名称。前缀与 名称之间用“_”分割,如:OP_CODE。

3。命名规则
规则3-6:类的方法的命名和过程、函数的 命名一样。 规则3-7:例程名以大写字母开始,且应在 具有不同词义单词的第一个字母处用大写。 规则3-8:设置输入参数值的例程名应当以 Set为其前缀,获取数值的例程名应当以 Get为其前缀。

3。命名规则
规则3-9:标识符的命名要清晰、明了,有 明确含义,同时使用完整的单词或大家基本 可以理解的缩写,避免使人产生误解。 说明:较短的单词可通过去掉“元音”形成缩 写;较长的单词可取单词的头几个字母形成 缩写;一些单词有大家公认的缩写。

3。命名规则
示例:如下单词的缩写能够被大家基本认可。 temp 可缩写为 tmp ; flag 可缩写为 flg ; statistic 可缩写为 stat ; increment 可缩写为 inc ; message 可缩写为 msg ;

3。命名规则
规则3-10:命名中若使用特殊约定或缩 写,则要有注释说明。 说明:应该在源文件的开始之处,对文件中 所使用的缩写或约定,特别是特殊的缩写, 进行必要的注释说明。

3。命名规则
规则3-11:对于变量命名,禁止取单个字 符(如i、j、k...),建议除了要有具体含 义外,还能表明其变量类型、数据类型等, 但i、j、k作局部循环变量是允许的。 说明:变量,尤其是局部变量,如果用单个 字符表示,很容易敲错(如i写成j),而编 译时又检查不出来,有可能为了这个小小的 错误而花费大量的查错时间。

3。命名规则
示例:下面所示的局部变量名的定义方法可以借鉴。 int iWidth 其变量名解释如下: i 数据类型(Interger) Width 变量含义

3。命名规则
建议3-1:变量名=前缀+助记符,助记命 名规则遵循骆驼法。
类型前缀 i s f d dm b l c 类型 int string float(single) double demical bool Long char

4。可读性
规则4-1:注意运算符的优先级,并用括号明确表 达式的操作顺序,避免使用默认优先级。 说明:防止阅读程序时产生误解,防止因默认的优 先级与设计思想不符而导致程序出错。

4。可读性(续)
示例:下列语句中的表达式 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。可读性(续)
规则4-2:避免使用不易理解的数字,用有意义的 标识来替代。涉及物理状态或者含有物理意义的常 量,不应直接使用数字,必须用有意义的枚举或宏 来代替。

4。可读性(续)
示例:如下的程序可读性差。 if (Trunk[index].trunk_state == 0) { Trunk[index].trunk_state = 1; ... // program code } 应改为如下形式。 #define TRUNK_IDLE 0 #define TRUNK_BUSY 1 if (Trunk[index].trunk_state == TRUNK_IDLE) { Trunk[index].trunk_state = TRUNK_BUSY; ... // program code }

4。可读性(续)
规则4-3:源程序中关系较为紧密的代码应尽可能 相邻。 说明:便于程序阅读和查找。
示例:以下代码布局不太合理。 rect.length = 10; char_poi = str; rect.width = 5; 若按如下形式书写,可能更清晰一些。 rect.length = 10; rect.width = 5; // 矩形的长与宽关系较密切,放在一起。 char_poi = str;

4。可读性(续)
规则4-4:不要使用难懂的技巧性很高的语句,除 非很有必要时。 说明:高技巧语句不等于高效率的程序,实际上程 序的效率关键在于算法。

4。可读性(续)
示例:如下表达式,考虑不周就可能出问题,也较难理解。 * stat_poi ++ += 1; * ++ stat_poi += 1; 应分别改为如下。 *stat_poi += 1; stat_poi++; ++ stat_poi; *stat_poi += 1; // 此二语句功能相当于“ * ++ stat_poi += 1; ” // 此二语句功能相当于“ * stat_poi ++ += 1; ”

5。变量、结构
规则5-1:去掉没必要的公共变量。 说明:公共变量是增大模块间耦合的原因之 一,故应减少没必要的公共变量以降低模块 间的耦合度。 规则5-2:仔细定义并明确公共变量的含 义、作用、取值范围及公共变量间的关系。 说明:在对变量声明的同时,应对其含义、 作用及取值范围进行注释说明,同时若有必 要还应说明与其它变量的关系。

5。变量、结构
规则5-3:结构的功能要单一,是针对一种 事务的抽象。 说明:设计结构时应力争使结构代表一种现 实事务的抽象,而不是同时代表多种。结构 中的各元素应代表同一事务的不同侧面,而 不应把描述没有关系或关系很弱的不同事务 的元素放到同一结构中。

5。变量、结构(续)
示例:如下结构不太清晰、合理。 typedef struct STUDENT_STRU { unsigned char name[8]; /* student's name */ unsigned char age; /* student's age */ unsigned char sex; /* student's sex, as follows */ /* 0 - FEMALE; 1 - MALE */ unsigned char teacher_name[8]; /* the student teacher's name */ unisgned char teacher_sex; /* his teacher sex */ } STUDENT;

5。变量、结构(续)
若改为如下,可能更合理些。 typedef struct TEACHER_STRU { unsigned char name[8]; /* teacher name */ unisgned char sex; /* teacher sex, as follows */ /* 0 - FEMALE; 1 - MALE */ } TEACHER; typedef struct STUDENT_STRU { unsigned char name[8]; /* student's name */ unsigned char age; /* student's age */ unsigned char sex; /* student's sex, as follows */ /* 0 - FEMALE; 1 - MALE */ unsigned int teacher_ind; /* his teacher index */ } STUDENT;

6。函数、过程
规则6-1:对所调用函数的错误返回码要仔 细、全面地处理。 规则6-2:编写可重入函数时,应注意局部 变量的使用(如编写C/C++语言的可重入 函数时,应使用auto即缺省态局部变量或 寄存器变量)。 说明:编写C/C++语言的可重入函数时, 不应使用static局部变量,否则必须经过特 殊处理,才能使函数具有可重入性。

6。函数、过程(续)
规则6-3:编写可重入函数时,若使用全局 变量,则应通过关中断、信号量(即P、V 操作)等手段对其加以保护。 说明:若对所使用的全局变量不加以保护, 则此函数就不具有可重入性,即当多个进程 调用此函数时,很有可能使有关全局变量变 为不可知状态。

6。函数、过程(续)
示例:假设Exam是int型全局变量,函数Squre_Exam返回Exam平方值。 那么如下函数不具有可重入性。 unsigned int example( int para ) { unsigned int temp; Exam = para; // (**) temp = Square_Exam( ); return temp; } 此函数若被多个进程调用的话,其结果可能是未知的,因为当(**)语句刚 执行完后,另外一个使用本函数的进程可能正好被激活,那么当新激活的进程 执行到此函数时,将使Exam赋与另一个不同的para值,所以当控制重新回 到“temp = Square_Exam( )”后,计算出的temp很可能不是预想中的 结果。此函数应如下改进。

6。函数、过程(续)
此函数若被多个进程调用的话,其结果可能是未知的,因为当(**)语句 刚执行完后,另外一个使用本函数的进程可能正好被激活,那么当新激活的进程 执行到此函数时,将使Exam赋与另一个不同的para值,所以当控制重新回到 “temp = Square_Exam( )”后,计算出的temp很可能不是预想中的结果。 此函数应如下改进。 unsigned int example( int para ) { unsigned int temp; [申请信号量操作] // 若申请不到“信号量”,说明另外的进程正处于 Exam = para; // 给Exam赋值并计算其平方过程中(即正在使用此 temp = Square_Exam( ); // 信号),本进程必须等待其释放信号后, [释放信号量操作] //才可继续执行。若申请到信号,则可继续执行, //但其它进程必须等待本进程释放信号量后,才能再使 // 用本信号。 return temp; }

6。函数、过程(续)
规则6-4:在同一项目组应明确规定对接口函数参 数的合法性检查应由函数的调用者负责还是由接口 函数本身负责,缺省是由函数调用者负责。 说明:对于模块间接口函数的参数的合法性检查这 一问题,往往有两个极端现象,即:要么是调用者 和被调用者对参数均不作合法性检查,结果就遗漏 了合法性检查这一必要的处理过程,造成问题隐 患;要么就是调用者和被调用者均对参数进行合法 性检查,这种情况虽不会造成问题,但产生了冗余 代码,降低了效率。

6。函数、过程(续)
规则6-5:防止将函数的参数作为工作变 量。 说明:将函数的参数作为工作变量,有可能 错误地改变参数内容,所以很危险。对必须 改变的参数,最好先用局部变量代之,最后 再将该局部变量的内容赋给该参数。

6。函数、过程(续)
示例:下函数的实现不太好。 void sum_data( unsigned int num, int *data, int *sum ) { unsigned int count; *sum = 0; for (count = 0; count < num; count++) { *sum += data[count]; // sum成了工作变量,不太好。 }

} 若改为如下,则更好些。

6。函数、过程(续)
若改为如下,则更好些。 void sum_data( unsigned int num, int *data, int *sum ) { unsigned int count ; int sum_temp; sum_temp = 0; for (count = 0; count < num; count ++) { sum_temp += data[count]; } } *sum = sum_temp;

6。函数、过程(续)
规则6-6:函数的规模尽量限制在200行以 内。 说明:不包括注释和空格行。 规则6-7:一个函数仅完成一件功能。

6。函数、过程(续)
规则6-8:为简单功能编写函数。 说明:虽然为仅用一两行就可完成的功能去 编函数好象没有必要,但用函数可使功能明 确化,增加程序可读性,亦可方便维护、测 试。

6。函数、过程(续)
示例:如下语句的功能不很明显。 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);

6。函数、过程(续)
规则6-9:函数的功能应该是可以预测的,也就是 只要输入数据相同就应产生同样的输出。 说明:带有内部“存储器”的函数的功能可能是不可 预测的,因为它的输出可能取决于内部存储器(如 某标记)的状态。这样的函数既不易于理解又不利 于测试和维护。在C/C++语言中,函数的static 局部变量是函数的内部存储器,有可能使函数的功 能不可预测,然而,当某函数的返回值为指针类型 时,则必须是STATIC的局部变量的地址作为返回 值,若为AUTO类,则返回为错针。

6。函数、过程(续)
示例:如下函数,其返回值(即功能)是不可预测的。 unsigned int integer_sum( unsigned int base ) { unsigned int index; static unsigned int sum = 0; // 注意,是static类型的。 // 若改为auto类型,则函数即变为可预测。 for (index = 1; index <= base; index++) { sum += index; } return sum; }

6。函数、过程(续)
规则6-10:尽量不要编写依赖于其他函数 内部实现的函数。 说明:此条为函数独立性的基本要求。由于 目前大部分高级语言都是结构化的,所以通 过具体语言的语法要求与编译器功能,基本 就可以防止这种情况发生。但在汇编语言 中,由于其灵活性,很可能使函数出现这种 情况。

6。函数、过程(续)
示例:如下是在DOS下TASM的汇编程序例子。过程Print_Msg的实现依赖 于Input_Msg的具体实现,这种程序是非结构化的,难以维护、修改。 ... // 程序代码 proc Print_Msg // 过程(函数)Print_Msg ... // 程序代码 jmp LABEL ... // 程序代码 endp proc Input_Msg // 过程(函数)Input_Msg ... // 程序代码 LABEL: ... // 程序代码 endp

6。函数、过程(续)
规则6-10:尽量不要编写依赖于其他函数 内部实现的函数。 说明:此条为函数独立性的基本要求。由于 目前大部分高级语言都是结构化的,所以通 过具体语言的语法要求与编译器功能,基本 就可以防止这种情况发生。但在汇编语言 中,由于其灵活性,很可能使函数出现这种 情况。

6。函数、过程(续)
规则6-11:避免设计多参数函数,不使用的参数 从接口中去掉。 说明:目的减少函数间接口的复杂度。 规则6-12:检查函数所有参数输入的有效性。 规则6-13:检查函数所有非参数输入的有效性, 如数据文件、公共变量等。 说明:函数的输入主要有两种:一种是参数输入; 另一种是全局变量、数据文件的输入,即非参数输 入。函数在使用输入之前,应进行必要的检查。。

6。函数、过程(续)
规则6-14:使用动宾词组为执行某操作的 函数命名。如果是OOP方法,可以只有动 词(名词是对象本身)。
示例:参照如下方式命名函数。 void print_record( unsigned int rec_ind ) ; int input_record( void ) ; unsigned char get_current_color( void ) ;

7。程序效率
规则7-1:循环体内工作量最小化。 说明:应仔细考虑循环体内的语句是否可以 放在循环体之外,使循环体内工作量最小, 从而提高程序的时间效率。

7。程序效率(续)
示例:如下代码效率不高。 for (ind = 0; ind < MAX_ADD_NUMBER; ind++) { sum += ind; back_sum = sum; /* backup sum */ } 语句“back_sum = sum;”完全可以放在for语句之后,如下。 for (ind = 0; ind < MAX_ADD_NUMBER; ind++) { sum += ind; } back_sum = sum; /* backup sum */

7。程序效率(续)
规则7-2:在多重循环中,应将最忙的循环 放在最内层。 说明:减少CPU切入循环层的次数。

7。程序效率(续)
示例:如下代码效率不高。 for (row = 0; row < 100; row++) { for (col = 0; col < 5; col++) { sum += a[row][col]; } } 可以改为如下方式,以提高效率。 for (col = 0; col < 5; col++) { for (row = 0; row < 100; row++) { sum += a[row][col]; } }

7。程序效率(续)
规则7-3:尽量减少循环嵌套层次。 规则7-4:避免循环体内含判断语句,应将 循环语句置于判断语句的代码块之中。 说明:目的是减少判断次数。循环体中的判 断语句是否可以移到循环体外,要视程序的 具体情况而言,一般情况,与循环变量无关 的判断语句可以移到循环体外,而有关的则 不可以。

7。程序效率(续)
示例:如下代码效率稍低。 for (ind = 0; ind < MAX_RECT_NUMBER; ind++) { if (data_type == RECT_AREA) { area_sum += rect_area[ind]; } else { rect_length_sum += rect[ind].length; rect_width_sum += rect[ind].width; } }

7。程序效率(续)
因为判断语句与循环变量无关,故可如下改进,以减少判断次数。 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; } }


相关文章:
2-C语言编程规范
C 语言编程规范文档编号:SR-OPD-GF-2 版本 变更原因 变更内容简述 增加注释规范...(6)结构和联合内的成员变量的定义遵循变量的命名规范中的局部变量命名方式 (7)...
C语言编程规范
C语言编程规范_信息与通信_工程科技_专业资料。今日推荐 180份文档 CET四级高分通关宝典 2014年6月大学英语六级考试真题及答案 2014年12月大学四级冲刺试题及答案...
C语言编程规范
C语言编程规范 此书送给喜欢C语言编程的同学。此书送给喜欢C语言编程的同学。隐藏...4 2.3 代码行内的空格(6 条规则+1 条建议)... ...
C语言编程规范和范例
{ ... // program code } 二、 注释 2.1 一致性保证注释与代码的一致性...( a ); 《C 语言编程规范》 内部 a++; // 结果:a = 6,即只执行了...
C语言编程规范
语言编程规范 C 语言编程规范 目 次 1 范围 ......1.24 代码行 规则 6.2.1:每行最多包含一个声明。 规则 6.2.2:if、for、while、do 等语句自占一行...
C语言编程规范简述
C语言编程规范简述_计算机软件及应用_IT/计算机_专业...(2)注释的内容要清楚、明了,含义准 确,防止注释...(6)命名规范必须与所使用的系统风格保持一致,并在...
C语言编程规范
6页 免费 c语言编程规范精华版 22页 2下载券 C语言编程规范1 39页 1下载券...算全的 C51 编程规范 附录 C/C++ 编码规范 引言 今天人们越来越明白软件设计...
2 C语言编程规范总则0608
C语言编程的一些规范C语言编程的一些规范隐藏>> 编程规范总则编程规范总则 1 排版 2 注释 3 标识符命名 4 可读性 5 变量、结构 6 函数、过程 7 程序效率 8...
C语言编程规范-1.0_图文
20 C 语言编码规范 1.文件结构(4 条规则+6 条建议) C程序文件通常分为两...(4 条规则+6 条建议) 【规则1-2-1】在复杂的工程文件中,为了防止头文件被...
C语言编程规范
5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 1. 2. 3. 4. 标准名称: C 语言编程规范 标准编号: 版次号:A 受控号: 拟制...
更多相关标签: