编程精粹--编写高质量C语言代码(5):为子系统设防(二)

 接着上一篇文章<<编程精粹--编写高质量C语言代码(4):为子系统设防(一)>>,继续以内存管理程序为例,讨论如何为子系统设防。

内存管理程序有一个问题就是当我们第一次创建内存块时知道其大小,但随后几乎马上就会失去这一信息。上一篇文章讲过,对于内存管理程序,检查指针的有效性不能仅仅检查指针是否为空,还需要检查这个指针是否指向某个有效内存。假如能够知道已分配内存块的数目及其在内存块中的具体存储位置,那么对于任意指针的值,我们都能够确定它是否有效。那我们如何能够得到这些信息,这就需要我们在程序中保存某种类型的分配日志。

假设有如下三个不同的调试界面(个人理解这本书中的“界面”一词代表的是“函数原型”),用来维护日志信息:

/* 为新分配的内存块建立一个内存记录 */

flag fCreateBlockInfo(byte* pbNew,size_t size_new);

/* 释放一个内存块所对应的的内存信息 */
void FreeBlockInfo(byte* pb)

/* 修改现有内存块对应的日志信息*/

void UpdateBlockInfo(byte* pbOld,byte* New,size_t size_new);

这几个函数的实现需要我们自己编写,至于实现方法不是很重要,只要他们不使相应的系统的运行速度降低到无法运用的程度。有了这几个日志函数,我们在上一篇文章实现的fNewMemory,FreeMemory,fResizeMemory这几个函数就需要调用相应的日志记录函数,来维护相应的日志信息。

          保存调试信息,以便进行更强的错误检查。

让我们继续思考,假如在我们的fResizeMemory函数实现中,我们在调用fNewMemory函数申请新的内存后,却忘记了调用FreeMemory释放原来老的内存。这样表面上不会有什么问题,但是指针指向新的内存,而原来老的内存却没有被释放,这就导致我们丢失了一块内存,因为唯一指向这块内存的指针已经指向了新的内存。

这类错误隐藏的非常深,因为它们不会引发任何不合法的情况发生。在相应数据没被用到的情况下相应的调试代码也没用,因为它查不出这些错误。要找出这些错误,就需要对错误“挨门挨户”的搜查。不要等待错误自己暴露出来,要在程序中加上能够积极地寻找这种问题的调试代码。所以我们需要保存相应的调试信息,然后对已知指针表进行比较,如果发现指针所引用的是尚未分配的内存或者已分配的内存却没有被任何指针所指向,我们就能发现问题。

          建立详尽的子系统检查并且经常地进行这些检查。

毫无疑问,所加入的调试代码会引起程序交付版本和调试版本之间的差别。但只要在加入调试代码十分谨慎,并没有改变原有程序的内部行为,那么这种区别就不应该有什么问题。还有一个问题就是调试代码会增加应用程序的大小。但是程序的调试版本的目的就是捕捉错误。

当编写调试代码的实现细节时,我们可能面对很多选择,对于每一种选择,我们都需要问自己“这种选择是会引起错误还是会帮助发现错误”。例如上一文中bGarbage值的选择。

          仔细设计程序的测试代码,任何选择都应该经过考虑。

最好的测试代码应该是透明的代码,不管程序员能否感觉到它们的存在,它们都应该起作用。精心设计子系统测试代码的好处—当测试代码把错误限制在一个局部范围之后,就通过断言把错误抓住并送到“广播室”,把正常的工作打断。

          努力做到透明的一致性检查。

这一章中,为了找到许多隐藏很深的错误,我们需要加入很多调试代码。但是我们并没有在程序的交付版本中加入任何测试代码,这些测试代码只用在它的调试版本。所以如果为内存管理程序加上日志程序可以帮助你发现各种难以捕捉的错误,那么就会皆大欢喜。

          不要把对交付版本的约束应用到相应的调试版本上,要用大小和速度来换取错误检查能力。


总结:

1,尽力使所编写的测试代码甚至在程序员对其没有感觉的情况下亦能起作用。最好的测试代码是不用知道其存在也能起作用的测试代码。

2,如果可能的话,要把测试代码放到所编写的子系统中,而不要把它放在所编写子系统的外层。在子系统设计的每一步,都要考虑“如何对这一实现进行详尽地确认”这一问题。

3,在由于速度太慢或者占用的内存太多而抛弃一个确认测试程序之前,要三思而后行。


最后,依然用书中的一句话总结这篇文章:

          重要的是要在感情上区分程序的调试版本和交付版本。调试版本是用来发现错误的,而交付版本则是用来取悦顾客的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值