分节阅读 8(1 / 1)

凑的代码。

说明:因为紧凑的代码并不代表高效的机器码。

9 质量保证

19-1:在软件设计过程中构筑软件质量。

19-2:代码质量保证优先原则

(1)正确性,指程序要实现设计要求的功能。

(2)稳定性、安全性,指程序稳定、可靠、安全。

(3)可测试性,指程序要具有良好的可测试性。

(4)规范/可读性,指程序书写风格、命名规则等要符合规范。

(5)全局效率,指软件系统的整体效率。

(6)局部效率,指某个模块/子模块/函数的本身效率。

(7)个人表达方式/个人方便性,指个人编程习惯。

19-3:只引用属于自己的存贮空间。

说明:若模块封装的较好,那么一般不会发生非法引用他人的空间。

19-4:防止引用已经释放的内存空间。

说明:在实际编程过程中,稍不留心就会出现在一个模块中释放了某个内存块(如c语言

指针),而另一模块在随后的某个时刻又使用了它。要防止这种情况发生。

19-5:过程/函数中分配的内存,在过程/函数退出之前要释放。

19-6:过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。

说明:分配的内存不释放以及文件句柄不关闭,是较常见的错误,而且稍不注意就有可能

发生。这类错误往往会引起很严重后果,且难以定位。

示例:下函数在退出之前,没有把分配的内存释放。

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

}

19-7:防止内存操作越界。

说明:内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件系统主

要错误之一,后果往往非常严重,所以当我们进行这些操作时一定要仔细小心。

示例:假设某软件系统最多可由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;

}

}

19-8:认真处理程序所能遇到的各种出错情况。

19-9:系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。

19-10:系统运行之初,要对加载到系统中的数据进行一致性检查。

说明:使用不一致的数据,容易使系统进入混乱状态和不可知状态。

19-11:严禁随意更改其它模块或系统的有关设置和配置。

说明:编程时,不能随心所欲地更改不属于自己模块的有关设置如常量、数组的大小等。

19-12:不能随意改变与其它模块的接口。

19-13:充分了解系统的接口之后,再使用系统提供的功能。

示例:在b型机的各模块与操作系统的接口函数中,有一个要由各模块负责编写的初始化

过程,此过程在软件系统加载完成后,由操作系统发送的初始化消息来调度。因此就涉及

到初始化消息的类型与消息发送的顺序问题,特别是消息顺序,若没搞清楚就开始编程,

很容易引起严重后果。以下示例引自b型曾出现过的实际代码,其中使用了

fid_fetch_data与fid_initial初始化消息类型,注意b型机的系统是在

fid_fetch_data之前发送fid_initial的。

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之前执行的,而初始化

alarm_module_list是在fid_fetch_data中进行的,故在fid_initial中(**)

处引用alarm_module_list变量时,它还没有被初始化。这是个严重错误。

应如下改正:要么把get_alarm_module函数放在fid_initial中(**)之前;要

么就必须考虑(**)处的判断语句是否可以用(不使用alarm_module_list变量的)

其它方式替代,或者是否可以取消此判断语句。

19-14:编程时,要防止差1错误。

说明:此类错误一般是由于把“<=”误写成“<”或“>=”误写成“>”等造成的,由此

引起的后果,很多情况下是很严重的,所以编程时,一定要在这些地方小心。当编完程序

后,应对这些操作符进行彻底检查。

19-15:要时刻注意易混淆的操作符。当编完程序后,应从头至尾检查一遍这些操作符,以防

止拼写错误。

说明:形式相近的操作符最容易引起误用,如c/c++中的“=”与“==”、“|”与“||”、

“&”与“&&”等,若拼写错了,编译器不一定能够检查出来。

示例:如把“&”写成“&&”,或反之。

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 ));

19-16:有可能的话,if语句尽量加上else分支,对没有else分支的语句要小心对待;switch

语句必须有default分支。

19-17:unix下,多线程的中的子线程退出必需采用主动退出方式,即子线程应return出口。

19-18:不要滥用goto语句。

说明:goto语句会破坏程序的结构性,所以除非确实需要,最好不使用goto语句。

.9-1:不使用与硬件或操作系统关系很大的语句,而使用建议的标准语句,以提高软件的可移

植性和可重用性。

.9-2:除非为了满足特殊需求,避免使用嵌入式汇编。

说明:程序中嵌入式汇编,一般都对可移植性有较大的影响。

.9-3:精心地构造、划分子模块,并按“接口”部分及“内核”部分合理地组织子模块,以提

高“内核”部分的可移植性和可重用性。

说明:对不同产品中的某个功能相同的模块,若能做到其内核部分完全或基本一致,那么

无论对产品的测试、维护,还是对以后产品的升级都会有很大帮助。

.9-4:精心构造算法,并对其性能、效率进行测试。

.9-5:对较关键的算法最好使用其它算法来确认。

.9-6:时刻注意表达式是否会上溢、下溢。

示例:如下程序将造成变量下溢。

unsigned char size ;

while (size-- >= 0) // 将出现下溢

{

... // program code

}

当size等于0时,再减1不会小于0,而是0xff,故程序是一个死循环。应如下修改。

char size; // 从unsigned char 改为char

while (size-- >= 0)

{

... // program code

}

.9-7:使用变量时要注意其边界值的情况。

示例:如c语言中字符型变量,有效值范围为-128到127。故以下表达式的计算存在一

定风险。

char ch