程序调试 ——基础与技巧 西安交通大学 王树升
概述 任何一个天才都不敢说,他编的程序是完全正确的。几乎每一个稍微复杂一点的程序都必须经过反复的调试,修改,最终才完成。所以说,程序的调试是编程中的一项重要技术。 在应用程序中发现并排除错误的过程叫做调试。 选用VS2005作为开发平台,语系为C系列(C,C++,C#)。
1. 错误 程序设计中常见的错误可以分为三种: 编译错误 运行时错误 逻辑错误
1.1 编译错误 编译错误是指程序在编译过程中出现的错误。它是由于不正确的编写代码而产生的如非法使用或丢失关键字、遗漏了某些必需的标点符号、函数调用缺少参数或传递了不匹配的参数等等。 例: fore(int i = 0; i < 100; i++)//关键字书写错误 {}
1.1编译错误
1.2 运行时错误 运行时错误是指应用程序在运行期间执行了非法操作或某些操作失败,如打开的文件未找到、磁盘空间不足、网络连接断开、除法中除数为零等等; 例:数组下标越界是一种典型的运行时错误。 int [] arrayX = new int [4]; for(int i = 0; i<5;i++){ arrayX[i] = i; }
1.2 运行时错误
1.2运行时错误
1.3逻辑错误 逻辑错误是指应用程序未按照预期的方式运行时所产生的错误。一般来讲,这不是属于语法层次的错误,应用程序可以执行,但是得不到正确的预期结果。 例: 对于一个数组的初始化,预期对其某个特定位置赋初始值,其余置零: int [] array = new int [100]; array[55] = 55; for(int i = 0;i<100;i++) array[i] = 0; 那么在这段代码完成后就没有得到我们预期的结果(代码执行顺序的逻辑错误)。
2.调试的类别 调试方法分为两种:动态调试和静态调试。 程序的静态调试就是在程序编写完以后,由人工“代替”“模拟”计算机,对程序进行仔细检查,主要检查程序中的语法规则和逻辑结构的正确性。实践表明,有很大一部分 错误可以通过静态检查来发现。通过静态调试,可以大大缩短上机调试的时间,提高上机的效率。
2.调试的分类 程序的动态调试就是实际上机调试,它贯穿在编译、连接和运行的整个过程中。根据程序编译、连接和运行时计算机给出的错误信息进行程序调试,这是程序调试中最 常用的方法,也是最初步的动态调试。在此基础上,通过“分段隔离”、“设置断点”、 “跟踪打印”进行程序的调试。 这里主要讲解动态调试。
2.1动态调试 调试应用程序的过程中,可以充分控制应用程序的执行过程,包括以不同的方式启动调试过程、中断应用程序的执行等等。 主要有: 开始执行F5(Go):应用程序开始执行并一直执行下去直到遇到断点或者程序结束。 逐语句Step Into(F11):应用程序开始执行第一条语句然后中断,当遇到有函数调用时,执行过程会进入到被调用函数的内部。
2.1动态调试 逐过程Step Over(F10):与逐语句相似,但是它不进入到被调用函数的内部,而是把函数调用当作是一条语句来执行。 Step Out(Shift+F11):与之相反,step out是跳出当前进程,返回到调用它的外层代码,该过程执行完毕。 Toggle Breakpoint(F9):在当前光标所在行添加断点。
2.1动态调试 VS05为用户提供了3种步进单位。 行:步进一次执行一行源代码。(有可能一行代码中有多条语句) 语句:步进一次执行一条语句。 指令:步进一次执行一条机器指令。 可以通过【调试】菜单中的【窗口】中修改调试方式来进行选择。
3.断点 断点是调试应用程序时经常使用的一种工具。 使用断点前必须要在代码中插入断点。(F9) VS中使用【新建断点】命令来选择断点类型以及设置“高级”断点。例如:点击次数是指断点所在位置运行的次数,到达条件时才中断程序。 各IDE请参照其技术手册。
3.一些较好的技巧 使用预定义(调试标记) 在编写程序的时候,往往需要获得一些中间信息例如制作日志文件来观察应用程序是否是按照我们预期来运行的。那么这个情况下就可以使用预处理#define定义调试标记。
3.一些较好的技巧 运行期间的调试标记 可以使用定义bool变量来决定是否执行调试语句。
3.一些较好的技巧 使用断言 c系列中的assert()断言的使用。
3.一些较好的技巧 最好写出备注 这是个良好的习惯,方便自己也方便后人。为关键变量以及各个函数功能写出言简意赅的注释。