网站大量收购闲置独家精品文档,联系QQ:2885784924

优质C程序秘诀--- 章 - 为子系统设防.docVIP

  1. 1、本文档共23页,可阅读全部内容。
  2. 2、有哪些信誉好的足球投注网站(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  5. 5、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  6. 6、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  7. 7、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  8. 8、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
优质C程序秘诀--- 章 - 为子系统设防

第3章 为子系统设防 在上一章中我们说过瓶颈子程序是加入断言的绝佳之处,因为它可以使我们用很少的代码就能够进行很彻底的错误检查。这就好象一个足球场,虽然可以有50000个球迷来看球,但如果检票人员站在球场的入口,那么只需要几个检票人员就够了。程序中也有这样的入口,这就是子系统的调用点。 例如,对于文件系统,用户可以打开文件、关闭文件、读写文件和创建文件。这是五个基本的文件操作,这些操作通常需要大量复杂代码的支持。有了这些基本的操作,用户就可以通过对它们的调用来完成相应的文件操作,而不必操心文件目录、自由存储空间映射或者特定硬件设备(如磁盘驱动器、磁带驱动器或联网设备)的读写等实现细节。 又如,对于内存管理程序,用户可以分配内存、释放内存,有时还可以改变分配了的内存的大小。这些操作同样需要许多代码的支持。 通常,子系统都要对其实现细节进行隐藏,所隐藏的实现细节可能相当复杂。在进行实现细节隐藏的同时,子系统为用户提供了一些关键的入口点。程序员通过调用这些关键的入口点来实现同子系统的通讯。因此如果在程序中使用这样的子系统并且在其调用点加上了调试检查,那么不用花很大力气就可以进行许多的错误检查。 例如,假如要求你为标准的C运行时间库编写malloc、free和realloc子程序(有时必须做这件事情),那么你可能会在代码中加上断言。你可能进行了彻底的测试,并已编写了极好的程序员指南。尽管如此,我们知道在使用这些程序时,用户还是会遇到问题。那么为了对用户有所帮助,我们可以作些什么呢? 这里给出的建议是:当子系统编写完成之后,要问自己:“程序员什么情况下会错误地使用这个子系统,在这个子系统中怎样才能自动地检查出这些问题?”在正常情况下,当开始编码排除设计中的危险因素时就应该问过了这个问题。但不管怎样,还应该再问一次。 对于内存管理程序。程序员可能犯的错误是: 分配一个内存块并使用其中未经初始化的内容; 释放一个内存块但继续引用其中的内容; 调用realloc对一个内存块进行扩展,因此原来的内容发生了存储位置的变化,但程序???用的仍是原来存储位置的内容; 分配一个内存块后即“失去”了它,因为没有保存指向所分配内存块的指针; 读写操作越过了所分配内存块的边界; 没有对错误情况进行检查。 这些问题并不是臆想出来的,它们每时每刻都存在。更糟的是,这些问题都具有不可再现的特点,所以很难发现。出现一次,就再也看不到了。直到某一天,用户因为被上面某个常见问题搞得一筹莫展而怒气冲冲地打电话来“请”你排除相应的错误时,才会被再次发现。 确实,这些错误都很难发现。但是,这并不是说我们没有什么可以改进的事情了。断言确实很有用,但要使断言发挥作用就必须使其能够被执行到。对于我们上面列出的问题,内存管理程序中的断言能够查出它们吗?显然不能。 在这一章中,将介绍一些用来肃清子系统中错误的其它技术。使用这些技术,可以免除许多麻烦。本章虽然以C的内存管理程序为例进行阐述,但所得到的结论同样适用于其它的子系统,无论是简单的链表管理程序,还是个多用户共享的正文检查工具都适用。 若隐若现,时有时无 通常,解决上述问题的方法是直接在子系统中加上相应的测试代码。但是出于两个理由,本书并没有这么做。第一个理由是我不想让例子中到处都是malloc、free和realloc的实现代码。第二个理由是用户有时得不到所用子系统的源代码。我之所以会这么说,是因为在用来测试本书例子的六个编译程序中,有两个提供了标准的源代码。 由于用户可能得不到子系统的源代码,或者即使能够得到,这些源代码的实现也未必都相同,所以本书不是直接在子程序的源代码中加上相应的测试代码,而是利用所谓的“外壳”函数把内存管理程序包装起来,并在这层包装的内部加上相应的测试代码。这就是在得不到子系统源代码的情况下所能采用的方法。在编写外壳函数时,将采用本书前面介绍过的命名约定。 下面我们先讨论malloc的外壳函数。它的形式如下: /* fNewMemory ─── 分配一个内存块 */ flag fNewMemory(void** pv, size_t size) { byte** ppb = (byte**)ppv; *ppb = (byte*)malloc(size); return(*ppb != NULL); /* 成功 */ } 该函数看起来比malloc要复杂,这主要是其指针参数void**带来的麻烦。但如果你看到程序员调用这一函数的方法,就会发现它比malloc的调用形式更清晰。有了fNewMemory,下面的调用形式: if( (pbBlock) = (byte*)malloc(32) != NULL ) 成功 ─── pbBlock指向所分配的内存块 else 不成功 ─── pbBlock等

您可能关注的文档

文档评论(0)

panguoxiang + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档