Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5174583
  • 博文数量: 1696
  • 博客积分: 10870
  • 博客等级: 上将
  • 技术积分: 18357
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-30 15:16
文章分类
文章存档

2017年(1)

2016年(1)

2015年(1)

2013年(1)

2012年(43)

2011年(17)

2010年(828)

2009年(568)

2008年(185)

2007年(51)

分类: WINDOWS

2010-08-30 14:53:10

应该说,调试的基本手段是断点。在VC++中设置一个断点很简单,装入源文件,把光标放在想要停止的代码行上,将鼠标指向Insert/Remove Breakpoint按钮,然后单击鼠标就可以了。这个过程称为“设置位置断点”。当运行到这一行代码的时候就会停下来,等待你的进一步操作。 

显然,能够在你希望的地方停下来,这很好。在这个时候你可以做许多事情。

1. 通过变量查看窗口查看变量的值
VC有三种查看窗口:AUTOS, LOCALS, WATCH。

AUTOS是VC根据当前语句行涉及到的数据显示相应的变量值,这样你总是能够看到那些你最关心的变量的值。
LOCALS是VC根据当前的上下文,显示最近的局部变量值。
WATCH则是你自己指定VC显示那些变量的值。
在AUTOS和LOCALS窗口中显示的值是自动格式的,你最多只能在十进制和十六进制之间切换,但是在WATCH窗口中则有很多参数。比如显示整型变量i的值,可以写:

i,u 将i显示为无符号的十进制整数
i,x 将i显示为十六进制整数
i,c 将i显示为单字符
这种格式码很多,具体可以看MSDN。此外,在WATCH中还能够显示CPU寄存器,例如:

@EAX,x 显示EAX寄存器的内容
你也可以在WATCH窗口中显示一个表达式,例如:

i+j
Object.m_strName
当然,你也可以把WATCH作为一个计算器使用:

1000/365
甚至你还能在WATCH中调用一个函数……(这可要小心一些才好^_^)

2. 查看堆栈
你可以在CALL STACK窗口中看到你的函数是如何调用的,例如:

demo.exe!main() Line 112
demo.exe!mainCRTStartup() Line259+0x12
kenerl32.dll!77e5eb69()
这说明在demo.exe模块中的mainCRTStartup()被kernerl32.dll模块中的77e5eb69()位置的函数调用了,而它又调用了demo.exe模块中的main()函数。

如果函数有参数,那么这些参数也会显示出来,你双击显示的某一行,就能调出相应的源代码。

3. 其它
你还能够让VC显示出多线程的运行信息、内存信息、模块信息、反汇编信息以及寄存器信息等,这里就不多说了。

好,一个断点中就能做这些事情,但是如果我要让它停在第10000个循环处,该怎么办?这里就要用到高级断点了。

在断点所在行按择鼠标右键,选择“Breakpoint Properties“,这里会出现一个"Condition"和"Hit Count"按钮(VC7,对于VC6稍有不同)。

在"Hit Count"中输入一个数字,这表示在停止运行前通过这个断点的次数,或者使用其它判断条件。
在"Condition"中输入一个条件表达式,表示如果满足这个条件则在这个断点停下。在这里,只能使用C类型比较运算符,不能调用任何函数,不能包含任何宏。在"Condition"中还能够选择当这个表达式的值改变后在断点停下。
通过使用高级断点能够大大增强调试器的功能,但是它还有其它的断点类型,通过进一步使用断点语法,能够设置更加详细、具体的断点。

从比较一般的讨论来说,调试可以分成以下几个步骤:

1. 复制错误
所谓复制错误,就是把错误再现出来,便于进一步对其进行分析。这是整个调试过程中非常重要的一个步骤。有时候这一步并不是十分容易,甚至有时候不能复制错误,这就要求本身对错误有一定的处理,最简单的就是把相关数据导出,例如在MFC中支持的DUMP功能等。

2. 分解错误
一旦错误再次出现以后,你就需要确定错误的发生地点。这有点像一个二分搜索算法,从大到小,逐步分解各个段。在这个阶段你需要对错误的原因进行不同的猜想,同时依据各种变量、对象的状态分析当前是否正常。通过逐步排除正确的段,把错误限定在一个较小的范围内。随着调试过程的不断进行,你的猜想会越来越准确,当你积累了一定的经验后,在某个时间时就能够“领悟”到错误的原因。

3. 解决错误
虽然找到了错误的原因,可是解决错误有时是很困难的,你会发现错误是源于对系统的错误设计,为了解决这个错误你需要对进行很大的改动,当然,也有相当一部分错误是很容易解决的。

4. 校验错误
一旦解决了错误后,一定要对改正的结果进行校验。在很多时候,你解决了一个错误会导致一些副作用,为此必须对你的更正进行校验。

上面是对调试很概貌性的说明。在这个过程中,你通常需要:

设法准确地描述错误。这里所说的描述,是你做好能够用自然语言完整地把错误说明一下,让你自己对错误有一个全面、完整地了解;
始终假定错误是你自己造成的。虽然确实存在编译和操作系统的错误,但是这种机会非常之少,所以,一般设计中的绝大部分的绝大部分错误都是设计者自己造成的;
要用边界数据和常规数据进行测试。你必须对你的的输入要有相当的了解,并用一些极端的数据进行测试。此外当你明确了一个原因的猜想后应当进一步考虑达成这个结果的各种输入条件,并尽量创造这些条件,必要时采取一些特殊的手段;
代码中增加一些自我测试的代码。虽然调试技术很多,可是基本的断言和跟踪仍然是非常有用的,其它一些功能,比如堆栈检测等也非常有效。使用这些系统提供的廉价诊断可以使你在崩溃前和崩溃时获得更多的信息,这样即使没有调试的支持,你也能获得一定的信息,便于确定错误的位置;
充分理解编译的提示。一些编译能够为员提供许多有价值的信息,例如绝大多数C++编译会出现大量的警告,尽管你可以忽视这些警告,但是我的经验发现几乎所有的警告都能够指出你的一个或者几个错误;
充分利用调试的功能。我看到过不少人几乎不会使用调试,或者仅仅使用一些简单的功能,实际上现代调试的功能已经不再是简单的单步执行了。在正确使用调试的过程中能够使你排除错误的速度大大提高;
最后,对于最终解决的错误应该有一个小结。员之间交流错误以及错误的排除对于其能力的提高有很大帮助。有了小结后不仅在交流时有可以交流的内容,也使自己对这个错误有进一步的理解。调试这件工作是非常需要经验的。
阅读(1587) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-12-28 18:06:17

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com

chinaunix网友2010-12-28 18:05:56

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com