软件调试(30)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
软件调试的原因?
任何一个天才都不敢说,他编的程序 是完全正确的。几乎每一个稍微复杂一 点的程序都必须经过反复的调试,修改, 最终才完成。所以说,程序的调试是编 程中的一项重要技术。 在应用程序中发现并排除错误的过程 叫做调试。
软件调试
什么是调试(Debug)?
• 软件调试是在进行了成功的测试之后才 开始的工作。它与软件测试不同,调试 的任务是进一步诊断和改正程序中潜在 的错误。 • 调试活动由两部分组成:
•暴力法调试 •归纳法 •演绎法 •回溯法 •测试法
应用以上任一种方法之前,都应当对错误的征兆进行全面彻底的 分析,得出对出错位置及错误性质的推测,再使用一种适当的调 试方法来检验推测的正确性。
强行排错
这种调试方法目前使用较多,效率较低。它不 需要过多的思考,比较省脑筋。例如:
– 通过内存全部打印来调试,在这大量的数据中寻找出错的位 置。 – 在程序特定部位设置打印语句,把打印语句插在出错的源程序 的各个关键变量改变部位、重要分支部位、子程序调用部位, 跟踪程序的执行,监视重要变量的变化。 – 自动调试工具。利用某些程序语言的调试功能或专门的交互 式调试工具,分析程序的动态过程,而不必修改程序。
归纳法调试
• 归纳法是一种从特殊推断一般的 系统化思考方法。 • 归纳法调试的基本思想是:从一 些线索(错误征兆)着手,通过分 析它们之间的关系来找出错误。
– 收集有关的数据 列出所有已知的测试用例和 程序执行结果。看哪些输入数据的运行结果是 正确的,哪些输入数据的运行结果有错误。 – 组织数据 由于归纳法是从特殊到一般的推断过程,所以需 要组织整理数据,以发现规律。 常以3W1H形式组织可用的数据: “What” 列出一般现象; “Where”说明发现现象的地点; “When” 列出现象发生时所有已知情况; “How” 说明现象的范围和量级;
磨刀不误砍柴功
• 熟悉当前的开发(调试)环境,比如:设置断点、单 步运行、全速运行、终止运行,查看RAM、查看堆栈、查 看IO口状态……总之,要熟练掌握基本操作的方法,并 深刻了解其中意义。 • 了解软件本身的可用资源和特性。 • 了解操作系统和一些硬件资源的知识。 • 掌握基本的调试技巧和常用的调试工具。 • 搜索、鉴别资料的能力。(内事问百度、外事问谷歌) • 与人沟通,描述问题的能力。(调试36计的最后一 计——就是向他人讨教。尤其是我们现在可以直接询问一 些技术支持,这使得我们解决问题更加便捷。当然,你得 把话说明白才行) • …… • 差不多了,如果上述6把砍柴刀磨好了,就可以开始调 试了。接下来,请调试你的程序……
– 确定程序中可疑错误的确切性质和位置。 – 对程序(设计,编码)进行修改,排除这个 错误。
调试的特点:
• 调试工作是一个具有很强技巧性的工作。 • 软件运行失效或出现问题,往往只是潜在错 误的外部表现,而外部表现与内在原因之间 常常没有明显的联系。如果要找出真正的原 因,排除潜在的错误,不是一件易事。
慢镜头的威力
• 如何实现这个慢镜头呢?方法很多: 1、单步运行 2、在每一步分动作之后设立断点 3、在每一步分动作之后插入足够的延时,让我 们可以看清楚这些分动作 • 通过慢镜头的反复回放,我们就可以发现,到底 是哪一个分动作出现了问题。
暴力调试的使用时机
• 其他方法都失败了 • 其他方法的补充,而不是替代
回溯法调试
• 这是在小程序中常用的一种有效的调试方法。 一旦发现了错误,人们先分析错误征兆,确定最先发现 “症状”的位置。然后,人工沿程序的控制流程,向回 追踪源程序代码,直到找到错误根源或确定错误产生的 范围。 • 例如,程序中发现错误处是某个打印语句。通过输出值 可推断程序在这一点上变量的值。再从这一点出发,回 溯程序的执行过程,反复考虑:“如果程序在这一点上 的状态(变量的值)是这样,那么程序在上一点的状态 一定是这样...”, 直到找到错误的位置。
调试的类别
• 调试方法分为两种:动态调试和静态调试。
• 程序的静态调试就是在程序编写完以后, 由人工“代替”“模拟”计算机,对程序 进行仔细检查,主要检查程序中的语法规 则和逻辑结构的正确性。实践表明,有很 大一部分 错误可以通过静态检查来发现。 通过静态调试,可以大大缩短上机调试的 时间,提高上机的效率。
运行时错误
运行时错误
4 逻辑错误
• 逻辑错误是指应用程序未按照预期的方式运行时所产生 的错误。一般来讲,这不是属于语法层次的错误,应用 程序可以执行,但是得不到正确的预期结果。 • 例: 对于一个数组的初始化,预期对其某个特定位置赋初始 值,其余置零: int [] array = new int [100]; array[55] = 55; for(int i = 0;i<100;i++) array[i] = 0; 那么在这段代码完成后就没有得到我们预期的结果(代 码执行顺序的逻辑错误)。
第三种类型
• 类似于在程序中插入打印语句,但不修改 程序 • 可以使用编程语言的调试功能 • 特点是可设置断点… • 也需要碰运气,会产生大量的无关数据
暴力调试主要问题
• 忽略了思考的过程 • 调试程序和侦破谋杀案有相似处 • 谜案都是通过仔细分析线索,将表面不重 要的线索联系起来,这不是一个使用蛮 力的方法
• 可以说,调试是通过现象,找出原因的一个 思维分析的过程。
调试——一项最不受欢迎的活动
• 个人自尊会从中阻挠 • 热情耗尽 • 可能迷失方向 • 必须自力更生
调试的步骤
(1) 从错误的外部表现形式入手,确定程序 中出错位置; (2) 研究有关部分的程序,找出错误的内在 原因; (3) 修改设计和代码,以排除这个错误; (4) 重复进行暴露了这个错误的原始测试或 某些有关测试。
调试的主要难点——技术上
• 现象与原因所处的位置可能相距甚远。 • 当其它错误得到纠正时,这一错误所表 现出的现象可能会暂时消失,但并未实 际排除。 • 现象实际上是由一些非错误原因(例如, 舍入不精确)引起的。 • 现象可能是由于一些不容易发现的人为 错误引起的。
调试的主要难点——技术上
• 错误是由于时序问题引起的,与处理 过程无关。 • 现象是由于难于精确再现的输入状态 (例如,实时应用中输入顺序不确定) 引起。 • 现象可能是周期出现的。在软、硬件 结合的嵌入式系统中常常遇到。
软件常见的错误类型
•语法错误 •编译错误 • 运行错误 • 逻辑错误
1 语法错误
• • • • 词法错误和句法错误。 例如:前边有{ ,后边缺少 } 参数该是整型的变量用了字符型 ……
2 编译错误
• 编译错误是指程序在编译过程中出现的错误。它 是由于不正确的编写代码而产生的如非法使用或 丢失关键字、遗漏了某些必需的标点符号、函数 调用缺少参数或传递了不匹配的参数等等。 • 例: fore(int i = 0; i < 100; i++)//关键字书写错 误 {}
错误分析
• 错误出现在什么地方? • 谁制造了这个错误? • 那些做的不正确? • 如何避免该错误的出现? • 为什么错误没有及早发现? • 该如何更早的发现错误?
调试技巧
• 指表现在艺术、工艺、体育等方面的巧 妙的技能。
优先调试人机界面
• 为什么要先调显示模块?道理很简单, 我们说“眼睛是心灵的窗户”,同样, “显示是程序的窗户”。一旦把显示模 块调试好了,就可以通过这个窗口,观 察 程序内部的数据和状态了。
– 证明假设 把假设与原始线索或数据进行比较,若它能 完全解释一切现象,则假设得到证明;否则, 就认为假设不合理,或不完全,或是存在多 个错误,以致只能消除部分错误。
演绎法调试
• 演绎法是一种从一般原理或前提出发,经 过排除和精化的过程来推导出结论的思考 方法。 • 演绎法排错是测试人员首先根据已有的测 试用例,设想及枚举出所有可能出错的原 因做为假设;然后再用原始测试数据或新 的测试,从中逐个排除不可能正确的假设; 最后,再用测试数据验证余下的假设确是 出错的原因。
确定错误的性质和位置的原则
• 用头脑去分析思考与错误征兆有关的信 息,避开死胡同。 • 如果遇到僵局,就留在稍后解决。 • 遇到困难,就把问题描述给别人听。 • 只把调试工具当做辅助手段来使用。利 用调试工具,可以帮助思考,但不能代 替思考。 • 避免用试探法,最多只能把它当做最后 手段。
修改错误的原则
–列举所有可能出错原因的假设 把所有可能的错误原因列成表。通过 它们,可以组织、分析现有数据。 –利用已有的测试数据,排除不正确的 假设 仔细分析已有的数据,寻找矛盾,力 求排除前一步列出所有原因。如果所 有原因都被排除了,则需要补充一些 数据(测试用例),以建立新的假设。
– 改进余下的假设 利用已知的线索,进一步改进余下的假 设,使之更具体化,以便可以精确地确 定出错位置。 – 证明余下的假设
软件调试
软件测试
什么是软件调试?
•软件调试的原因? •什么是软件调试? • 软件调试的特点 • 调试步骤 •调试的主要难点
DEBUG的由来
1937年,美国青年霍德华.艾肯找到IBM公司 为其投资200万美元研制计算机,第一台成品 艾肯把它取名为:马克1号(mark1) 为马克1号编制程序的是哈佛的一位女数学家 格蕾丝· 莫雷· 霍波,有一天,她在调试程序时 出现故障,拆开继电器后,发现有只飞蛾被夹 扁在触点中间,从而“卡”住了机器的运行 霍波诙谐的把程序故障统称为“臭虫 (BUG)”,把排除程序故障叫DEBUG
“Yes”描述出现错误的3W1H; “No”作为比较,描述了没有错 误的3W1H。通过分析找出矛盾 来。
–提出假设 分析线索之间的关系,利用在线索结构中观察到 的矛盾现象,设计一个或多个关于出错原因的假 设。如果一个假设也提不出来,归纳过程就需要 收集更多的数据。此时,应当再设计与执行一些 测试用例,以获得更多的数据。
编译错误
3 运行时错误
• 运行时错误是指应用程序在运行期间执行 了非法操作或某些操作失败,如打开的文 件未找到、磁盘空间不足、网络连接断开、 除法中除数为零等等; • 例:数组下标越界是一种典型的运行时错 误。 int [] arrayX = new int [4]; for(int i = 0; i<5;i++){ arrayX[i] = i; }
调试的分类
• 程序的动态调试就是实际上机调试,它 贯穿在编译、连接和运行的整个过程中。 根据程序编译、连接和运行时计算机给 出的错误信息进行程序调试,这是程序 调试中最常用的方法,也是最初步的动 态调试。在此基础上,通过“分段隔 离”、“设置断点”、 “跟踪打印”进 行程序的调试。
几种主要的调试方法
第一种类型
• 难以在内存区域与变量之间建立对应关系 • 内存信息数量庞大,大多数与调试无关 • 内存信息输出是静态快照,是某一刻的状态,需 要的是跟踪动态状态 • 内存信息很少可以精确地在错误发生地方产生 • 通过分析输出的内存信息发现问题的办法不多
第二种类型
• 它不是鼓励我们思考程序中的问题,而主要是 一种碰运气的方法 • 它所产生的需要分析的数据量非常庞大 • 它要求我们修改程序,这些修改可能会掩盖掉 错误,改变关键时序关系,或者会引入新错误 • 它可能对小程序有效,大型程序成本相当高,而 且对于一些类型的程序,甚至无法使用.
• • • • • 在出现错误的地方,很可能还有别的错误。 应纠正错误本省,而不是症状。 正确纠正错误的可能性并非100% 正确修改错误的可能性随着程序的规模增加而降低 当心修正一个错误的同时有可能会引入新的错误。
• 修改错误的过程将迫使人们暂时回到程序设计阶段。 • 修改源代码程序,不要改变目标代码。
测试法调试
• 使用测试用例。供调试的测试用例,目 的是提供有用的信息,定位某个被怀疑 的错误 • 当发现缺陷的症状后,会编写供调试的 测试用例,发现错Baidu Nhomakorabea位置 • 不是一种独立的方法,常结合归纳法或 演绎法一起使用
调试原则
• 在调试方面,许多原则本质上是 心理学方面的问题。调试由两部 分组成,调试原则也分成两组。