《Effective Debugging:软件和系统调试的66个有效方法》——第21条:把属于同一个类型的所有问题全都修复好

第21条:把属于同一个类型的所有问题全都修复好

在某一个地方所发生的问题,也有可能出现在其他地方。之所以会这样,可能是因为开发者在这些地方都采用了相同的思路来编程,也有可能是因为使用了某个很容易遭到误用的API,或把错误的代码从一个地方复制到了其他很多地方。在许多较为成熟的开发环境或对安全要求很高的工作场合中,开发者并不会在修复了某一个问题之后就止步于此,而是会把属于同一类型的所有问题全都解决好,以防将来再出现类似的错误。

例如,你发现下面这条语句的除数可能会是0,并且已经将该问题解决了:

那么,接下来你还应该搜索整个代码,看看有没有其他地方也把totalWeight用作除数。你可以通过IDE或Unix的grep命令(参见第22条)来搜索:

做完了这一步之后,还应该考虑代码中有没有其他地方也会出现类似的除法问题。我们需要寻找并修复这些可能出错的地方。借助Unix的管道机制,可以轻松地实现这种搜索。下面这段命令,能够在四百万行C语言代码里面,把可能出现除法问题的地方找出来。


经过几次过滤之后,可疑的代码从5731行降为5045行,又降为2032行,最后只剩下1923行。这个代码量,使得我们可以在合理的时间范围之内,将其中的代码审视一遍。尽管过滤得并不是特别严谨(例如,sizeof有可能返回0、符号常量的值有可能是0),但毕竟可以使我们知道其中有哪些代码可能出现问题。这要比那种以工作量过大为借口而根本不去检查除法代码的做法好很多。

最后我们还要考虑的是:怎样在将来的工作中避免类似的错误。这可能需要我们对代码或者软件开发流程做一些调整。例如,如果程序总是由于误用某个API函数而出错,那么可以提供一个更为安全的版本,并且把原来的版本屏蔽掉。例如,在项目的全局include文件里面,可以写上这么一行代码:

根据上述定义,如果有人试图在程序里面使用gets函数(该函数很容易发生缓冲区溢出的问题),那么代码就无法编译或链接。如果程序是因为对类型错误的值进行处理而出错的,那么可以考虑进行更为严格的类型检查。此外,还可以通过运用静态分析技术或更为严谨的配置方案来找到许多程序错误(参见第51条)。

要点

  • 修复了某一个错误之后,我们还需要寻找并解决其他相似的错误,并设法保证将来不会再出现此类错误。
时间: 2024-10-29 07:30:10

《Effective Debugging:软件和系统调试的66个有效方法》——第21条:把属于同一个类型的所有问题全都修复好的相关文章

《Effective Debugging:软件和系统调试的66个有效方法》——导读

前 言 我们在开发软件或对运行软件的系统进行管理的时候,经常会遇到故障.有些故障是因代码问题而引发的编译错误,这种故障可以在短时间内修复:还有一些故障则会使大型系统停机,这将给公司带来每小时数百万的损失(具体货币单位依情况而定).要想成为一名优秀的专业人士,你就必须在发生故障时迅速找出背后的原因并加以修复.这正是调试的意义所在,也是本书所要谈论的主题. 本书是写给有一定经验的开发者看的,而不是一本介绍性质的读物.它假设读者能够理解用各种编程语言所写成的代码片段,并且会使用高级的GUI编程工具以及

《Effective Debugging:软件和系统调试的66个有效方法》一导读

前 言 我们在开发软件或对运行软件的系统进行管理的时候,经常会遇到故障.有些故障是因代码问题而引发的编译错误,这种故障可以在短时间内修复:还有一些故障则会使大型系统停机,这将给公司带来每小时数百万的损失(具体货币单位依情况而定).要想成为一名优秀的专业人士,你就必须在发生故障时迅速找出背后的原因并加以修复.这正是调试的意义所在,也是本书所要谈论的主题. 本书是写给有一定经验的开发者看的,而不是一本介绍性质的读物.它假设读者能够理解用各种编程语言所写成的代码片段,并且会使用高级的GUI编程工具以及

《Effective Debugging:软件和系统调试的66个有效方法》一第6条:使用软件自身的调试机制

第6条:使用软件自身的调试机制 程序是一种很复杂的东西,因此它们通常都包含内置的调试机制.(至于怎样给自己正在开发的软件里面添加这样的机制,请参见第40条.)这种机制有很多好处,其中包括:我们可以通过禁用后台执行或多线程执行等特性来简化程序的调试工作.我们可以有选择地执行其中某一部分功能,以便通过测试用例来精确地再现相关的故障.程序可以给我们提供与性能有关的报表及其他信息.程序可以把更多的信息记录在日志文件中.因此,我们应该花一些时间,看看自己要调试的这款软件内置了哪些调试机制.想要了解这些机制

《Effective Debugging:软件和系统调试的66个有效方法》——第20条:开始调试之前与调试完毕之后都要把程序清理干净

第20条:开始调试之前与调试完毕之后都要把程序清理干净 如果你要调试的软件有10个地方可能出错,那么这些错误就会有上千种(2的10次方)表现形式,如果有20个地方可能出错,那么表现形式就会高达一百多万种(2的20次方).因此,在调试的时候,应该优先关注当前区域中最容易解决的那些问题.例如: 能够借助工具而找到的问题(参见第51条). 程序在运行时所产生的警告(例如,可恢复的断言失败). 读起来比较费解,而且与你要调试的bug有所关联的那些代码(参见第48条). 标有XXX.FIXME及TODO字

《Effective Debugging:软件和系统调试的66个有效方法》一第8条:把工作焦点放在最为重要的问题上

第8条:把工作焦点放在最为重要的问题上 许多大型软件系统都含有数量极其众多的bug(有一些是已知的bug,还有一些则尚未发现).要想高效地进行调试,就必须把应该受到关注的bug与可以忽略的bug明智地区分开.这样做不是为了单纯地缩减事务清单中的未决事务,而是为了帮助我们开发出稳定.易用.可维护而且效率较高的软件,毕竟这才是公司给我们支付薪水的原因.为此,我们要通过事务追踪系统来设定各项事务的优先级(参见第1条),从而使自己能够把工作重心汇聚在优先级较高的那些事务上,并把优先级较低的事务忽略掉.下

《Effective Debugging:软件和系统调试的66个有效方法》——第8条:把工作焦点放在最为重要的问题上

第8条:把工作焦点放在最为重要的问题上 许多大型软件系统都含有数量极其众多的bug(有一些是已知的bug,还有一些则尚未发现).要想高效地进行调试,就必须把应该受到关注的bug与可以忽略的bug明智地区分开.这样做不是为了单纯地缩减事务清单中的未决事务,而是为了帮助我们开发出稳定.易用.可维护而且效率较高的软件,毕竟这才是公司给我们支付薪水的原因.为此,我们要通过事务追踪系统来设定各项事务的优先级(参见第1条),从而使自己能够把工作重心汇聚在优先级较高的那些事务上,并把优先级较低的事务忽略掉.下

《Effective Debugging:软件和系统调试的66个有效方法》——第6条:使用软件自身的调试机制

第6条:使用软件自身的调试机制 程序是一种很复杂的东西,因此它们通常都包含内置的调试机制.(至于怎样给自己正在开发的软件里面添加这样的机制,请参见第40条.)这种机制有很多好处,其中包括: 我们可以通过禁用后台执行或多线程执行等特性来简化程序的调试工作. 我们可以有选择地执行其中某一部分功能,以便通过测试用例来精确地再现相关的故障. 程序可以给我们提供与性能有关的报表及其他信息. 程序可以把更多的信息记录在日志文件中. 因此,我们应该花一些时间,看看自己要调试的这款软件内置了哪些调试机制.想要了

《Effective Debugging:软件和系统调试的66个有效方法》一第13条:使自己尽可能多地观察到与调试有关的数据

第13条:使自己尽可能多地观察到与调试有关的数据 我们在调试的过程中要处理大量数据,并且要把各式各样的数据关联起来,如源代码.日志文件中的条目.变量的值.栈的内容.程序的I/O以及测试的结果等.这些数据通常是由多个处理流程与计算主机所产生的,如果能够把它们全都适当地展示在调试者眼前,那么将会给调试工作带来很多的好处.首先,可以使我们发现数据之间的相互关系.例如,我们可以看到:当测试失败的时候,日志文件中会多出来一条记录.其次,它可以令人尽量保持专注,避免因为来回切换而使思路受到干扰.有时我们必须

《Effective Debugging:软件和系统调试的66个有效方法》——第13条:使自己尽可能多地观察到与调试有关的数据

第13条:使自己尽可能多地观察到与调试有关的数据 我们在调试的过程中要处理大量数据,并且要把各式各样的数据关联起来,如源代码.日志文件中的条目.变量的值.栈的内容.程序的I/O以及测试的结果等.这些数据通常是由多个处理流程与计算主机所产生的,如果能够把它们全都适当地展示在调试者眼前,那么将会给调试工作带来很多的好处.首先,可以使我们发现数据之间的相互关系.例如,我们可以看到:当测试失败的时候,日志文件中会多出来一条记录.其次,它可以令人尽量保持专注,避免因为来回切换而使思路受到干扰.有时我们必须