1.6.4 程序调试

无论使用何种编程语言和编程工具,调试(Debug)的基本原理和步骤都是一样的。

(1)首先,通过人工检查的方式粗略判断出错误所在的范围,若无法判断,则认为被执行的第一行代码可能有错误。

(2)然后在范围的起始处设置断点,并以调试方式执行程序。当程序执行到断点处时,会暂时停止执行。

(3)接着,查看相关的变量或感兴趣的表达式在这一刻的实际值与预期值(即人脑计算出来的值,假设该值总是正确的)是否一致。若一致,则让程序从该断点处继续执行下一行代码。重复这一过程直至发现不一致,此时,被执行完的最后一行代码就是错误所在的位置。

注意:在对比实际值与预期值的过程中,还要对比程序的实际执行流程是否与预期流程一致,这对于定位分支、循环等结构中错误代码所在的位置尤为有用。

编程工具一般会提供诸如设置断点、查看变量或表达式,以及让程序从断点处执行下一行或下若干行代码的功能。JDK也提供了用于调试程序的工具——jdb.exe,但该工具是基于命令行的,在实际使用中非常不方便,对于较为复杂的程序,通常借助IDE来调试(详见附录A)。

人工检查与调试这两种判断逻辑错误所在位置的方式,读者都应当熟练掌握,当程序逻辑较为复杂时,应优先考虑使用调试方式。当然,调试方式也有着自身的局限性,对于某些特定的程序,有时很难用调试的方式来定位逻辑错误,如多线程程序[3]。对于这样的程序,可以采用一些辅助的技巧来帮助寻找逻辑错误。例如,在程序的合适位置添加输出语句,将变量或表达式的值输出到命令行窗口,以观察程序的运行细节、注释或取消注释某些代码行并结合排除法判断错误所在行等。

总而言之,在定位程序的逻辑错误时,没有一种方法能适用于所有场合。编程时,应学会并尽量遵守某些已被证明是行之有效的编码规范和最佳实践(详见附录C),以最大限度地减少逻辑错误的出现机会。当错误不可避免地发生时,应当根据错误所表现的具体特征以及实际情况,灵活运用多种方式来分析和定位逻辑错误。


[1]对于不存在编译过程的解释型语言,运行具有语法错误的程序时,运行环境将直接抛出错误。

[2]要求比较严格的软件项目可能会规定代码必须符合“零警告”。

[3]若在多线程程序的代码中设置断点,程序会因该断点而暂停执行其他线程。另外,由于CPU对多个线程的准确调度时机是无法预期的,断点的设置将影响实际的线程执行顺序。换句话说,对于完全相同的代码和数据,程序的运行逻辑和结果与用户选择让程序从断点处继续向后执行的时机有关,这使得对程序的调试具有了不确定性。