Windows程序调试----简介

来源:互联网 发布:淘宝怎么这么费4g流量 编辑:程序博客网 时间:2024/04/29 20:48

简介

    错误是无处不在的。程序产生错误的原闵很多,也有很多防止、检侧和消除错误的策略、工具和技术。随着软件开发技术的提高,软件的复杂程度也提高了,调试工怍更难于进行。程序员们为开发出完美的无错误软件而不懈地努力。伹这个目标在现实中是很难实现的。

    复杂性是开发无错误软件的主要障碍。即使是开发最普通的程序,不经过细致的测试和调试,也不能断定其中不含任何错误。复杂庞大的程序是错误产生率很高的原因,编程工作却是最不能允许错误或不精确的人类话动。可以考虑一下,在没有编译器帮助的情况下,编写很短的一段没有语法错误的程序就不是一件容.易的事情,更何况维护语法正确比保证语义正确相比,还是容易得多了。由此可以看出开发仟何复杂度的软件都需要调试。如果你编写的软件是用于商业目的的,那么调试更是生存的唯一出路。

    革新是开发无错误软件的另一个障碍。就在人们接近那把用于消除某类程序错误的钥匙时,有人却把锁给换了。现今的程序设计技术与五年前的相比,不管是外表上还是设计上都有本质的区别。许多非常有效的基于C语言的Windows API程序凋试技术,对如今的基于C++MFC类库程序几乎不起任何作用。同样地,COM技术、分布式COM技术、ATL技术和多线程Windows程序也给调试领域带来了新的挑战,具有讽刺意味的是,含有大量错误的软件的持续存在,可以说是快速发展的技术革新带来的一大成就。也可以这么说,能够轻松地编写无错误软件的时候就是新技术不再出现的那一天。这个结论不是逃避,而是对于“我们创造错误的能力远远大于我们消除它们的能力”这一事实的认知。

    紧密的开发进度也是开发无错误软件的障碍之一。理想中我们希望程序没有错误。但我们更希望它能在一个合理的进度安排下上市。管理人员对于维持进度的重视程度远远大于对于质量的重视,这也不是完全没有道理的。理想中的无错误软件往往需要太多的时间,以至于不能在这样一个竞争的商业环境下制作,因为客户不想等。在准确的市场时机上交付使用的即使是含有错误的软件,也可以带来利润,但是没有及时上市的完美程序却连一个子儿也赚不到。软件一般有有限的上市期,程序越晚上市,投资的冋报时间就越少。而且,在市场时机己经过去,市场中的领导地位己经确立后,产品就很难挣钱了。你可以在以后经常修补错误,但失去市场时机后就很难取回投资了。现实中有很多远远不是无错误程序却取得成功的例子。

调试的定义

    在深入探讨之前,我们先来确定一下调试的定义.并且和相关测试活动对比一下。

    错误(bug),是程序执行中的缺陷,也可以说是代码中的差错。如果程序不能如预期的那样运行,我们就说它含有错误。显然,崩溃不是程序预期的动作,所以崩溃是错误。那么,如果程序运行速度很慢,或在拖动窗口时闪烁呢?从实际意图出发,这些性能中不理想的地方都可以称为错误。我习惯称之为小错误,虽然这些问题不令人满意,需要修改,但这些并没有严重到影响它的上市。

    那么如何看待设计上的不足呢?比如可用性问题、界面不够友好了,或者不必要的重复命令了。从我们的定义看来,如果程序如预期那样运行,这些问题就不是错误。它们是设计上的失误造成的,不是程序实现上的错误。可能有人坚持认为设计不足也是错误,但是消除设计上的不足的过程,与消除实现上的错误的过程是完全不同的。毕竟,不能通过设置断点或察看调用堆栈来消除设计上的不足。所以,虽然用户和测试人员可能将设计不足看作错误,而记录在错误报告中,但是消除这些问题的方法是通过改变设计方案,而不是通过除去源代码中的错误。

    调试就是预防、揭示、诊断和消除错误的过程。充分利用编译器、连接器和其他开发工具可以预防错误的产生,也可以通过使用某种可以预防特定种类错误的编程方式。通过在代码中加入调试语句(如断言语句),可以在程序执行时使错误自动暴露出来。当然,也可以尽量收集有关错误的信息,然后利用调试器寻找问题的根源所在,即诊断错误。当成功地消除了已有的错误,并且没有新的错误产生时,调试过程就结束了。从调试的定义可以看出,它有许多特性:它是前摄的(发现错误之前)、有效的(错误发现之后)、静态的(分析源代码)和动态的(执行程序)

    调试过程几乎包含了消除错误的全部步骤,除了一个很重要的步骤——测试。测试就是积极地检测错误的过程。测试既包括为了发现错误而人工运行程序的过程,也包括制作并运行自动程序使测试自动化的过程。测试过程也需要专门的用于测试的代码的开发。如果不连接那些用于揭露错误的调试代码,比如断言与跟踪等语句,程序仍是完整的,所以测试代码并不是程序源代码的一部分。准确地说,测试代码是独立的,只有在测试过程中才加入到源代码中。

    对比一下这两个过程,测试发生在没有发现错误但却试图发现错误的时候,相反地,调试是编写代码预防错误或消除错误。调试经常是由程序员完成,需要修改代码,而任何人都可以测试一个程序,并不需要对源代码的了解。虽然调试和测试紧密结合,但它们的过程却完全不一样。此书集中介绍调试过程,但也讨论了一些与调试有关的测试过程。

调试目标

    本书主要讲实现调试目标的各种方法。调试的目的显然在于消除错误,但是如果想掌握高超的调试技能就必须更加努力。调试对于软件开发效率和软件质量至关重要。因此,从软件开发过程的观点来看,调试有以下目标。

l  效率。调试提供了一种预防错误且尽可能地发现错误的代码开发方式。有效的错误预防、检测和消除是减少人力浪费的必须。

l  质量。调试有助于发现错误的本质原因,且在不引入新错误的情况下消除它们。有效的错误预防、检测和消除是保证软件质量的必须。

    有效的调试可以在许多方面提高软件开发效率,但当你精通相关调试技能后,这种提高就更明显了,很多公司拥有专门的调试和质量监测小组,他们负责査找程序员遗留下来的错误。从效率的角度来说,程序员造成的错误的数量和大小与其他人査找错误的能力有关。当然,更好的方式是,程序员査找并消除尽可能多的错误,这样调试人员就只要査找遗漏下来的很少的错误就可以了。

    为了说明查找错误的方式如何影响开发的效率,我们比较一下这样两个过程。下面这个过程用于程序员自己査找并消除错误:

l  测试,发现了错误。

l  跟踪错误的产生,消除错误,验证这次修改的正确性。

    比较起来,如果测试人员发现错误,开发小组要使用一个不同的过程:

l  程序的新版本发布了。

l  测试小组安装程序。

l  测试小组提出测试方案。

l  测试人员发现了错误。

l  测试人员书写错误报告,提交给管理部门。

l  管理部门检阅错误报告,交给合适的程序员,假设碰巧是你。

l  你浏览错误报告,很可能询问测试人员些相关信息。

l  你重现错误。

l  你跟踪错误的产生,消除错误,验证这次修改的正确件。

l  你更新错误报告数据库,记叙这次修改。

l  你更新程序,将它发回给测试人员。

l  测试人员安装修正过的程序,浏览错误报。

l  测试人员确认错误已经被清除,且没有产生新的错误。

l  测试人员更新错误报告数据库。

l  [可选]即使错误被清除了,在程序上市前的每个星期你都必须参加错误情况会议,而且管理人员还会问你错误是否真地被修正了。

    这个过程,当然是情况发展比较顺利的时候,测试人员能够发现错误,你可以在第一次尝试的时候就重现并消除它。但如果不是这样,这个过程将变得异常复杂。这两个过程都需要程序员重现和消除错误,但是用到测试人员的过程就牵扯了更多的人,也就需要更多的时间来进行沟通和管理等工作。机能不良的调试过程有这样一个特点,就是它永远都在持续地做着试图结束这个工作的事情。现在你可以了解调试的重要性了吧。

    有些人认为调试在软件质量过程中并不占有一席之地,他们认为软件质量是在开始时就固定在程序里的。这种言辞只会误导别人。完美的设计,实现却很草率,甚至充满着错误,这在任何人的概念里都是质暈差的软件。

    如果软件不可能完全没有错误,那么它应该如何面对余留的错误呢?这个问题从软件本身的角度提出了两个目标。在存在问题的情况下,程序必须保证以下两点:

l  预防垃圾数据。如果继续运行程序,可能会有损害数据或被这些数据控制的外设的危险,那么这个程序必须被中止,不能破坏这些数据。

l  继续运行。如果继续运行并不会损害数据或外设,这个程序就可以继续运行(可能是在一个退化状态下)。如果问题很重大,就需要通知用户,由用户来决定关闭程序还是继续运行。

    如果这两点目标没有达到,就会使原始错误更加严重。第二个目标与当前大多数程序的作为恰恰相反,这些程序在一检测到错误时就自动中止。但是,这种自动中止并不是用户最想要的,尤其是在工作可以挽回却丢失的情况下。如果程序不能决定数据的状态和它保留这些数据的能力,就可以将数据保存在临时文件中,让用户来决定是否数据值得保留(PS:Office就是如此)

对更好的调试技术的需求

    调试显然是一项重要的编程技术。程序员常常需要比开发时间一半还多的时间,去测试和调试代码,但是他们很少花力气去提高调试技术。在这方面,调试技术就像天气一样。虽然每人都会谈论它,但没有任何人去对付它。如果认真地面对它,任何程序员的测试技术都会提高。考虑一下程序员在调试上花的时间,你会奇怪这么多的力气居然没有花在提高调试技术上。

    缺乏这种努力的一个原囚是调试技术很难学习。这并不是说关于调试技术没有足够的知识。相反,这些知识的数量之大足以让你淹没其中,但是它们的质量却从非常有帮助到一点用处也没有都有分布。比如,为了写这本书,我们参考了40多本书籍,将近100篇杂志论文,许多MSDN。文章、在线文章、时事通讯文章、会议记录等等,一盘录像带,数以百记的新闻组讨论。典型的讨论调试知识的文章不多,它们要么只是肤浅地介绍一下调试过程,要么过分深入地处理一个狭窄的调试论题,这些调试论题是从其他调试研究和关注分离出来的。对这些信息进行分类需要很多时间和很强的动力,从我们身上就可以得到证明。由于信息缺乏系统性和连贯性,调试不是可以让某人宣称自己是这方面大师的一门技术。但是却可以在不怕断积累中变得丰富。

战略性调试

    写这本书的主要目的是为了确认调试问题和介绍基木调试知识,以便你更加有效地使用Visual C++调试Windows程序。重点介绍可用于商业软件开发的实用解决方案。这本书的最终目的是使你的编程劳动更多产,软件更可靠。

    我们试着从战略的角度介绍调试基本技术。就是说,并不是简单地描述调试技术,然后说些“这种技术好极了,你可以不受限制地使用”之类的话,而是介绍了一种战略上的方法,不但讨论如何使用这种调试技术,而且说明了为什么使用、什么时候使用以及这祌方法在其他调试开发中如何移植。我们坚信,使用一个系统的方法远比使用那些混乱的调试技术取得的结果要好得多。

    我们选择了Visual C++和它的MFCATL应用程序框架作为调试的环境,其中很多方法也可以适用于其他Windows C++的开发环境,甚至其他Windows编程语言。但是,人的精力毕竞是有限的,我们还是愿意集中在一个特定的环境下进行讲叙,而将到其他环境和编程语言的移植作为练习留给读者。很多情况下,这种移植很容易,这是我们从经验中得到的,因为参考的40多本书中只有3本专门介绍了Visual C++中的调试。

0 0
原创粉丝点击