## 1.3 什么是调试 编程本身是一个复杂的过程,并且由人类而不是机器完成,所以经常会发生一些错误。由于一些奇怪的原因,程序中的错误称为bug,而追踪定位bug并且将其修正的过程则称为调试(Debug)。 程序中发生的错误有不同的种类,知道如何分辨不同的错误可以更快速地定位bug的位置。 ### 1.3.1 编译时错误 编译器只能编译语法正确的程序,否则会导致编译过程失败,无法运行程序。__语法__指的是程序结构以及与该结构相关的规则。 以英语语法为例,一个句子必须以大写字母开头,句号结尾。诸如“this sentence contains a syntax error.”和“So does this one”这样的两个句子都包含语法错误。 对大多数读者来说,少量语法错误并不是什么大问题。这就是为什么我们可以毫无障碍地阅读E.E.卡明斯的诗歌。 但是编译器并不是如此的宽容。如果你的程序中出现一处语法错误,编译器就会输出错误消息并且退出,而你就无法再运行自己的程序。 更糟糕的是,C++中具有比英语更多的语法规则,并且大多数时候你从编译器得到的错误消息都没有太大帮助。在你刚开始学习编程的时候,你很可能会花费大量的时间查找语法错误。不过随着你经验日益丰富,发生和查找错误需要的时间都会越来越少。 ### 1.3.2 运行时错误 第二种错误是运行时错误。将其称为运行时错误,是因为该错误只有在程序运行时才会发生。 接下来的几周我们要写的各种程序中,运行时错误很少发生。所以你可能需要一段时间才会遇到1。 > 注释:1这不是个好事情吗?——译者注 ### 1.3.3 逻辑和语义错误 第三种错误是__逻辑__和__语义__错误。如果程序中出现逻辑和语义错误,计算机不会产生任何错误消息,编译和运行过程都会成功。但是程序并没有做它应该做的,而是做了其他的事。只有在极少情况下它才会做你让它做的。 问题在于你写的程序不是你本意想写的程序,程序的意义(语义)有错误。识别逻辑错误是一件很棘手的事情,因为它需要你回头查看程序的输出并且尝试发现哪里出错了。 ### 1.3.4 实验调试 在本书的学习过程中,你应当获得的最重要的技能之一就是调试。尽管错误的出现让你沮丧,但是调试是编程过程中最需要脑力、最富有挑战性而且最有趣的部分了。 在某些方面调试就像侦察。你需要面对线索,推断出具体过程和事件,这些过程和事件能够得到你所看到的结果。 同时,调试又像是科学实验。一旦你想出来哪里可能出错了,你就会修改你的程序再次尝试。如果你的假设成立,你可以预测到修改后的结果并离可工作的程序更近一步。如果假设失败了,你需要提出一个新的假设。正如福尔摩斯所说,“当你排除了一切不可能的因素之后,剩下的无论看起来有多么不合理,也一定是事实。”(来自柯南道尔的《四个人的签名》)。 对一些人来说,编程和调试是同一件事情。也就是说,编程的过程就是逐步调试直到程序完成你想要的功能的过程。这种观点表明,任何时候你都应该从一个可以正常运行的程序入手,然后进行小的改动并调试通过,这样你的程序可以一直工作。 比如,Linux操作系统包含成千上万行代码,但是它最开始也只是 Linux Torvalds用于探索英特尔 80386芯片的简单程序。Larry Greenfield说:“Linus早期的工程之一就是一段在输出AAAA和BBBB之间切换的程序。然后进化成了Linux。”(来自Linux用户指导测试版1)。 在稍后的章节里,我会提出关于调试和编程练习的更多建议。