时间:2008-06-22 点击: 次 来源:本站原创 作者:亚九 - 小 + 大
目 录 1 排版 6 2 注释 11 3 标识符命名 18 4 可读性 20 5 变量、结构 22 6 函数、过程 28 7 可测性 36 8 程序效率 40 9 质量保证 44 10 代码编辑、编译、审查 50 11 代码测试、维护 52 12 宏 53
11-1:程序块要采用缩进风格编写,缩进的空格数为4个。
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;
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)
&& (act_task_table[taskno].result_data != 0));
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 }
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 );
rect.length = 0; rect.width = 0;
应如下书写
rect.width = 0;
if (pUserCR == NULL) return;
应如下书写: if (pUserCR == NULL) { return; }
for (...) { ... // program code }
if (...) { ... // program code }
{ ... // program code }
应如下书写。 for (...) { ... // program code }
if (...) { ... // program code }
void example_fun( void ) { ... // program code }
由于留空格所产生的清晰性是相对的,所以,在已经非常清晰的语句中没有必要再留空格, 在长语句中,如果需要加的空格非常多,那么应该保持整体清晰,而在局部不加空格。给
示例: (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)
/************************************************* Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. File name: // 文件名 Author: Version: Date: // 作者、版本及完成日期 Description: // 用于详细说明此程序文件完成的主要功能,与其他模块 // 或函数的接口,输出值、取值范围、含义及参数间的控 // 制、顺序、独立或依赖等关系 Others: // 其它内容的说明 Function List: // 主要函数列表,每条记录应包括函数名及功能简要说明 1. .... History: // 修改历史记录列表,每条修改记录应包括修改日期、修改 // 者及修改内容简述 1. Date: Author: Modification: 2. ... *************************************************/
Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. 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 ***********************************************************/ 说明:Description一项描述本文件的内容、功能、内部各部分之间的关系及本文件与
/************************************************* Function: // 函数名称 Description: // 函数功能、性能等的描述 Calls: // 被本函数调用的函数清单 Called By: // 调用本函数的函数清单 Table Accessed: // 被访问的表(此项仅对于牵扯到数据库操作的程序) Table Updated: // 被修改的表(此项仅对于牵扯到数据库操作的程序) Input: // 输入参数说明,包括每个参数的作 // 用、取值说明及参数间关系。 Output: // 对输出参数的说明。 Return: // 函数返回值的说明 Others: // 其它说明 *************************************************/
说明:在使用缩写时或之前,应对缩写进行必要的说明。 12-8:注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释) 例1: /* get replicate sub system index and net indicator */
repssn_ind = ssn_data[index].repssn_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;
/* active statistic task number */ #define MAX_ACT_TASK_NUMBER 1000
/* 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*/ };
/* The ErrorCode when SCCP translate */ /* Global Title failure, as follows */ // 变量作用、含义 /* 0 - SUCCESS 1 - GT Table error */ /* 2 - GT error Others - no use */ // 变量取值范围 /* only function SCCPTranslate() in */ /* this modual can modify it, and other */ /* module can visit it through call */ /* the function GetGTTransErrorCode() */ // 使用方法 BYTE g_GTTranErrorCode;
示例:如下例子,排版不整齐,阅读稍感不方便。 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 }
/* code one comments */ program code one /* code two comments */ program code two
应如下书写 /* code one comments */ program code one
/* code two comments */ program code two
case CMD_UP: ProcessUp(); break;
case CMD_DOWN: ProcessDown(); break;
case CMD_FWD: ProcessFwd();
if (...) { ... break; } else { ProcessCFW_B(); // now jump into case CMD_A }
case CMD_A: ProcessA(); break;
case CMD_B: ProcessB(); break;
case CMD_C: ProcessC(); break;
case CMD_D: ProcessD();
...
示例:如下注释意义不大。 /* if receive_flag is TRUE */ if (receive_flag)
而如下的注释则给出了额外有用的信息。 /* if mtp receive a message from links */ if (receive_flag)
示例:参见如下例子。 if (...) { // program code
while (index < MAX_INDEX) { // program code } /* end of while (index < MAX_INDEX) */ // 指明该条while语句结 } /* end of if (...)*/ // 指明是哪条if语句结束
13-1:标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的 示例:如下单词的缩写能够被大家基本认可。 temp 可缩写为 tmp ; flag 可缩写为 flg ; statistic 可缩写为 stat ; increment 可缩写为 inc ; message 可缩写为 msg ;
示例:下面所示的局部变量名的定义方法可以借鉴。 int liv_Width 其变量名解释如下: l 局部变量(Local) (其它:g 全局变量(Global)...) i 数据类型(Interger) v 变量(Variable) (其它:c 常量(Const)...) Width 变量含义
#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 );
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 add_user( BYTE *user_name ); int delete_user( BYTE *user_name );
14-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)造成了判断条件出错。
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;
}
示例:以下代码布局不太合理。 rect.length = 10; char_poi = str; rect.width = 5;
若按如下形式书写,可能更清晰一些。 rect.length = 10; rect.width = 5; // 矩形的长与宽关系较密切,放在一起。 char_poi = str;
示例:如下表达式,考虑不周就可能出问题,也较难理解。 * stat_poi ++ += 1;
* ++ stat_poi += 1;
应分别改为如下。 *stat_poi += 1; stat_poi++; // 此二语句功能相当于“ * stat_poi ++ += 1; ”
++ stat_poi; *stat_poi += 1; // 此二语句功能相当于“ * ++ stat_poi += 1; ”
示例:在源文件中,可按如下注释形式说明。 RELATION System_Init Input_Rec Print_Rec Stat_Score Student Create Modify Access Access Score Create Modify Access Access, Modify
注:RELATION为操作关系;System_Init、Input_Rec、Print_Rec、Stat_Score 其中,函数Input_Rec、Stat_Score都可修改变量Score,故此变量将引起函数间较
示例:如下例子(在DOS下BC3.1环境中),在移植时可能产生问题。 void main() { register int index; // 寄存器变量
_AX = 0x4000; // _AX是BC3.1提供的寄存器“伪变量” ... // program code }
示例:如下结构不太清晰、合理。 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;
若改为如下,可能更合理些。
{ 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;
示例:如下两个结构的构造不合理。 typedef struct PERSON_ONE_STRU { unsigned char name[8]; unsigned char addr[40]; unsigned char sex; unsigned char city[15]; } PERSON_ONE;
typedef struct PERSON_TWO_STRU { unsigned char name[8]; unsigned char age; unsigned char tel; } PERSON_TWO;
由于两个结构都是描述同一事物的,那么不如合成一个结构。 typedef struct PERSON_STRU { unsigned char name[8]; unsigned char age; unsigned char sex; unsigned char addr[40]; unsigned char city[15]; unsigned char tel; } PERSON;
示例:假如认为如上的_PERSON结构元素过多,那么可如下对之划分。 typedef struct PERSON_BASE_INFO_STRU { unsigned char name[8]; unsigned char age; unsigned char sex; } PERSON_BASE_INFO;
typedef struct PERSON_ADDRESS_STRU { unsigned char addr[40]; unsigned char city[15]; unsigned char tel; } PERSON_ADDRESS;
typedef struct PERSON_STRU { PERSON_BASE_INFO person_base; PERSON_ADDRESS person_addr; } PERSON;
示例:如下结构中的位域排列,将占较大空间,可读性也稍差。 typedef struct EXAMPLE_STRU { unsigned int valid: 1; PERSON person; unsigned int set_flg: 1; } EXAMPLE;
若改成如下形式,不仅可节省1字节空间,可读性也变好了。 typedef struct EXAMPLE_STRU { unsigned int valid: 1; unsigned int set_flg: 1; PERSON person ; } EXAMPLE;
unsigned short int exam;
chr = -1; exam = chr; // 编译器不产生告警,此时exam为0xFFFF。
示例:可参考如下方式声明自定义数据类型。
下面的声明可使数据类型的使用简洁、明了。 typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD;
下面的声明可使数据类型具有更丰富的含义。 typedef float DISTANCE; typedef float SCORE;
示例:假如有如下短整数及结构。 unsigned short int exam; typedef struct EXAM_BIT_STRU { /* Intel 68360 */ unsigned int A1: 1; /* bit 0 7 */ unsigned int A2: 1; /* bit 1 6 */
} EXAM_BIT;
如下是Intel CPU生成短整数及位域的方式。 内存: 0 1 2 ... (从低到高,以字节为单位) 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)在内存中的位置正好与内存的字边界
------- ------- ------- ------- | long1 | long1 | long1 | long1 | ------- ------- ------- ------- | | | | long2 | ------- ------- ------- -------- | long2 | long2 | long2 | | ------- ------- ------- -------- | ....
16-1:对所调用函数的错误返回码要仔细、全面地处理。
示例:假设Exam是int型全局变量,函数Squre_Exam返回Exam平方值。那么如下 unsigned int example( int para ) { unsigned int temp;
Exam = para; // (**) temp = Square_Exam( );
return temp; }
此函数若被多个进程调用的话,其结果可能是未知的,因为当(**)语句刚执行完后,另 unsigned int example( int para ) { unsigned int temp;
[申请信号量操作] // 若申请不到“信号量”,说明另外的进程正处于 Exam = para; // 给Exam赋值并计算其平方过程中(即正在使用此 temp = Square_Exam( ); // 信号),本进程必须等待其释放信号后,才可继 [释放信号量操作] // 续执行。若申请到信号,则可继续执行,但其 // 它进程必须等待本进程释放信号量后,才能再使 // 用本信号。 return temp; }
示例:下函数的实现不太好。 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成了工作变量,不太好。 } }
若改为如下,则更好些。 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; }
示例:如下语句的功能不很明显。 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);
示例:如下函数,其返回值(即功能)是不可预测的。 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; }
示例:如下是在DOS下TASM的汇编程序例子。过程Print_Msg的实现依赖于 ... // 程序代码 proc Print_Msg // 过程(函数)Print_Msg ... // 程序代码 jmp LABEL ... // 程序代码
proc Input_Msg // 过程(函数)Input_Msg ... // 程序代码 LABEL: ... // 程序代码 endp
示例:如下函数构造不太合理。 int add_sub( int a, int b, unsigned char add_sub_flg ) { if (add_sub_flg == INTEGER_ADD) { return (a + b); } else { return (a .. b); } }
不如分为如下两个函数清晰。 int add( int a, int b ) { return (a + b); }
{ return (a .. b); }
void print_record( unsigned int rec_ind ) ; int input_record( void ) ; unsigned char get_current_color( void ) ;
说明:避免用含义不清的动词如process、handle等为函数命名,因为这些动词并没有 建议6-15:函数的返回值要清楚、明了,让使用者不容易忽视错误情况。 说明:函数的每种出错返回值的意义要清晰、明了、准确,防止使用者误用、理解错误或 .6-16:除非必要,最好不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或
在编程时,经常遇到在不同函数中使用相同的代码,许多开发人员都愿把这些代码提出来, 示例:如下函数就是一种随机内聚。 void Init_Var( void ) { Rect.length = 0; Rect.width = 0; /* 初始化矩形的长与宽 */
Point.x = 10; Point.y = 10; /* 初始化“点”的坐标 */ }
矩形的长、宽与点的坐标基本没有任何关系,故以上函数是随机内聚。 应如下分为两个函数: void Init_Rect( void ) { Rect.length = 0; Rect.width = 0; /* 初始化矩形的长与宽 */ }
void Init_Point( void ) { Point.x = 10; Point.y = 10; /* 初始化“点”的坐标 */
扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,如总是1, 扇入越大,表明使用此函数的上级函数越多,这样的函数使用效率高,但不能违背函数间 较良好的软件结构通常是顶层函数的扇出较高,中层函数的扇出较少,而底层函数则扇入
(2)仔细考查模块或函数出错处理及模块的性能要求并进行完善。 (3)通过分解或合并函数来改进软件结构。 (4)考查函数的规模,过大的要进行分解。 (5)降低函数间接口的复杂度。 (6)不同层次的函数调用要有较合理的扇入、扇出。 (7)函数功能应可预测。 (8)提高函数内聚。(单一功能的函数内聚最高) 说明:对初步划分后的函数结构应进行改进、优化,使之更为合理。
示例:在某过程中较多引用TheReceiveBuffer[FirstSocket].byDataPtr, 则可以通过以下宏定义来代替: # define pSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr
17-1:在同一项目组或产品组内,要有一套统一的为集成测试与系统联调准备的调测开关及相
示例:下面是C语言中的一个断言,用宏来设计的。(其中NULL为0L) #ifdef _EXAM_ASSERT_TEST_ // 若使用断言测试
void exam_assert( char * file_name, unsigned int line_no ) { printf( "\n[EXAM]Assert failed: %s, line %u\n", file_name, line_no ); abort( );
#define EXAM_ASSERT( condition ) if (condition) // 若条件成立,则无动作 NULL; else // 否则报告 exam_assert( __FILE__, __LINE__ )
#else // 若不使用断言测试
#define EXAM_ASSERT(condition) NULL
#endif /* end of ASSERT */
int exam_fun( unsigned char *str ) { EXAM_ASSERT( str != NULL ); // 用断言检查“假设指针不为空”这个条件
... //other program code }
#define EXAM_CONNECTIONLESS 0 // 无连接业务 #define EXAM_CONNECTION 1 // 连接业务
int msg_process( EXAM_MESSAGE *msg ) { unsigned char service; /* message service class */
EXAM_ASSERT( msg != NULL );
service = get_msg_service_class( msg );
EXAM_ASSERT( service != EXAM_CONNECTION ); // 假设不使用连接业务
... //other program code }
对编译器提供的功能及特性假设可用断言检查,原因是软件最终产品(即运行代码或机器 示例:用断言检查编译器的int型数据占用的内存空间是否为2,如下。 EXAM_ASSERT( sizeof( int ) == 2 );
#ifdef _EXAM_ASSERT_TEST_ // 若使用断言测试
/* Notice: this function does not call 'abort' to exit program */ void assert_report( char * file_name, unsigned int line_no ) { printf( "\n[EXAM]Error Report: %s, line %u\n", file_name, line_no ); }
#define ASSERT_REPORT( condition ) if ( condition ) // 若条件成立,则无动作 NULL; else // 否则报告 assert_report ( __FILE__, __LINE__ )
#define ASSERT_REPORT( condition ) NULL
#endif /* end of ASSERT */
int msg_handle( unsigned char msg_name, unsigned char * msg ) { switch( msg_name ) { case MSG_ONE: ... // 消息MSG_ONE处理 return MSG_HANDLE_SUCCESS;
... // 其它合法消息处理
default: ... // 消息出错处理 ASSERT_REPORT( FALSE ); // “合法”消息不成立,报告 return MSG_HANDLE_ERROR; } }
示例:如下记录学生学习成绩的结构不合理。 typedef unsigned char BYTE; typedef unsigned short WORD;
typedef struct STUDENT_SCORE_STRU
BYTE name[8]; BYTE age; BYTE sex; BYTE class; BYTE subject; float score; } STUDENT_SCORE;
因为每位学生都有多科学习成绩,故如上结构将占用较大空间。应如下改进(分为两个结 typedef struct STUDENT_STRU {
BYTE age; BYTE sex; BYTE class; } STUDENT;
typedef struct STUDENT_SCORE_STRU { WORD student_index; BYTE subject; float score; } STUDENT_SCORE;
示例:如下代码效率不高。 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 */
示例:如下代码效率不高。 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]; } }
示例:如下代码效率稍低。 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; } }
因为判断语句与循环变量无关,故可如下改进,以减少判断次数。 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; }
示例:如下表达式运算可能要占较多CPU资源。 #define PAI 3.1416 radius = circle_length / (2 * PAI);
应如下把浮点除法改为浮点乘法。 #define PAI_RECIPROCAL (1 / 3.1416 ) // 编译器编译时,将生成具体浮点数 radius = circle_length * PAI_RECIPROCAL / 2;
(2)稳定性、安全性,指程序稳定、可靠、安全。 (3)可测试性,指程序要具有良好的可测试性。 (4)规范/可读性,指程序书写风格、命名规则等要符合规范。 (5)全局效率,指软件系统的整体效率。 (6)局部效率,指某个模块/子模块/函数的本身效率。 (7)个人表达方式/个人方便性,指个人编程习惯。
示例:下函数在退出之前,没有把分配的内存释放。 typedef unsigned char BYTE;
int example_fun( BYTE gt_len, BYTE *gt_code ) { BYTE *gt_buf;
gt_buf = (BYTE *) malloc (MAX_GT_LENGTH); ... //program code, include check gt_buf if or not NULL.
/* global title length error */ if (gt_len > MAX_GT_LENGTH) { return GT_LENGTH_ERROR; // 忘了释放gt_buf }
... // other program code }
应改为如下。 int example_fun( BYTE gt_len, BYTE *gt_code ) { BYTE *gt_buf;
gt_buf = (BYTE * ) malloc ( MAX_GT_LENGTH ); ... // program code, include check gt_buf if or not NULL.
/* global title length error */ if (gt_len > MAX_GT_LENGTH) { free( gt_buf ); // 退出之前释放gt_buf return GT_LENGTH_ERROR; }
... // other program code }
示例:假设某软件系统最多可由10个用户同时使用,用户号为1-10,那么如下程序存在 #define MAX_USR_NUM 10 unsigned char usr_login_flg[MAX_USR_NUM]= "";
void set_usr_login_flg( unsigned char usr_no ) { if (!usr_login_flg[usr_no]) { usr_login_flg[usr_no]= TRUE; } }
当usr_no为10时,将使用usr_login_flg越界。可采用如下方式解决。 void set_usr_login_flg( unsigned char usr_no ) { if (!usr_login_flg[usr_no - 1]) { usr_login_flg[usr_no - 1]= TRUE; } }
MID alarm_module_list[MAX_ALARM_MID];
int FAR SYS_ALARM_proc( FID function_id, int handle ) { _UI i, j;
switch ( function_id ) { ... // program code
case FID_INITAIL: for (i = 0; i < MAX_ALARM_MID; i++) { if (alarm_module_list[i]== BAM_MODULE // **) || (alarm_module_list[i]== LOCAL_MODULE) {
for (j = 0; j < ALARM_CLASS_SUM; j++) { FAR_MALLOC( ... ); } } }
... // program code
break;
case FID_FETCH_DATA:
... // program code
Get_Alarm_Module( ); // 初始化alarm_module_list
break;
... // program code } }
由于FID_INITIAL是在FID_FETCH_DATA之前执行的,而初始化 应如下改正:要么把Get_Alarm_Module函数放在FID_INITIAL中(**)之前;要
示例:如把“&”写成“&&”,或反之。 ret_flg = (pmsg->ret_flg & RETURN_MASK); 被写为: ret_flg = (pmsg->ret_flg && RETURN_MASK);
rpt_flg = (VALID_TASK_NO( taskno ) && DATA_NOT_ZERO( stat_data )); 被写为: rpt_flg = (VALID_TASK_NO( taskno ) & DATA_NOT_ZERO( stat_data ));
unsigned char size ; while (size-- >= 0) // 将出现下溢 { ... // program code }
当size等于0时,再减1不会小于0,而是0xFF,故程序是一个死循环。应如下修改。 char size; // 从unsigned char 改为char while (size-- >= 0) { ... // program code }
char chr = 127; int sum = 200;
chr += 1; // 127为chr的边界值,再加1将使chr上溢到-128,而不是128。 sum += chr; // 故sum的结果不是328,而是72。
若chr与sum为同一种类型,或表达式按如下方式书写,可能会好些。 sum = sum + chr + 1;
(2)不能过分相信其正确性。 (3)除非必要,不要使用不熟悉的第三方工具包与控件。 说明:使用工具包与控件,可加快程序开发速度,节省时间,但使用之前一定对它有较充
示例: #pragma warn -rvl // 关闭告警 int examples_fun( void ) { // 程序,但无return语句。 } #pragma warn +rvl // 打开告警 编译函数examples_fun时本应产生“函数应有返回值”告警,但由于关掉了此告警信
112-1:用宏定义表达式时,要使用完备的括号。 #define RECTANGLE_AREA( a, b ) a * b #define RECTANGLE_AREA( a, b ) (a * b) #define RECTANGLE_AREA( a, b ) (a) * (b) 正确的定义应为: #define RECTANGLE_AREA( a, b ) ((a) * (b))
#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++) {
}
#define SQUARE( a ) ((a) * (a))
int a = 5; int b; b = SQUARE( a++ ); // 结果:a = 7,即执行了两次增1。
正确的用法是: b = SQUARE( a ); a++; // 结果:a = 6,即只执行了一次增1。
|
上一篇:挑战你的理工学识:算
下一篇:42天学会英语短文