搜档网
当前位置:搜档网 › VC调试方法大全

VC调试方法大全

VC调试方法大全
VC调试方法大全

一、调试基础 调试快捷键

F5:

开始调试

Shift+F5:

停止调试

F10 : 调试到下一句,这里是单步跟踪 F11 :

调试到下一句,跟进函数内部

跟踪调试

1、尽量使用快捷键时行调试

2、观察调试信息

3、高级中断设置

异常调试 重试— > 取消— > 调试 函数堆栈,用variables 或者call stack 窗口

Release 调试

经常测试你的Debug 和Release 版本

不要移除调试代码,如用 ASSERT, TRACE 等。

初始化变量,特别是全局变量, malloc 的内存,new 的内存

当你移除某个资源时,确保你移除了所有跟这个资源相关的申明(主要是在 resouce.h 文中)

使用3或者4级的警告级编译你的代码,并确保没有警告, Project->setting->c/c++->warninglevel (

版是项目-> 属性->C/C++-> 常规— > 警告等级)

6、—debug 改成 NDEBUG 进行调试,project->setting->C/C++->Preprocessordefinitions >属性->C/C++->

预处理器-> 预处理定义)(这里是debug 和Release 编译的重要不同之一)

VC 调试方法大全

VC 调试方法大全

Shift+F11: 从当前函数中跳出

Ctrl+F10: 调试到光标所在位置 F9: 设置(取消)断点 Alt+F9:

高级断点设置

中文

(中文版是项目-

7、在 Release 中调试源代码,project->setting->C/C++->debug info 选择ProgramDataBase (中文版是项

目-> 属性->C/C++-> 常规-> 调试信息格式-> 用于编辑并继续"的程序数据库),Project — >setting->link 选上

Generate debug info ( 中文版是项目-> 属性-> 链接器-> 调试-> 生成调试信息)

8、走读代码,特别关注堆栈和指针

二、TRACE 宏 当选择了 Debug 目标,并且afxTraceEnabled 变量被置为TRUE 时,TRACE 宏也就随之被激活了。但在程序的

Release 版本中,它们是被完全禁止的。下面是一个典型的

TRACE 语句:

int nCount =9;

CString strDesc("total");

TRACE("Count =%d,Descri ption =%s\n",nCount,strDesc);

可以看到,TRACE 语句的工作方式有点像C 语言中的printf 语句,TRACE 宏参数的个数是可变的,因此使用起来非 常容易。如果查看 MFC 的源代码,你根本找不到TRACE 宏,而只能看到TRACE0、TRACE1、TRACE2和

TRACE3宏,它们的参数分别为 0、1、2、3。

个人总结:最近看网络编程是碰到了 TRACE 语句,不知道在哪里输出,查了一晚上资料也没找出来,今天终于找到 了,方法如下:

1.在MFC 中加入TRACE 语句

2.在 TOOLS->MFCTRACER 中选择 “ ENABLE TRACING ”点击 OK

3.进行调试运行,G0(F5)(特别注意:不是执行!'以前之所以不能看到TRACE 内容,是因为不是调试执行,而是

!‘了,切记,切记)

口,在那里就看到TRACE 的内容了, 以下是找的TRACE 的详细介绍:

TRACE 宏对于VC 下程序调试来说是很有用的东西,有着类似

出现,当RELEASE 的时候该宏就完全消失了,从而帮助你调式也在 使用非常简单,格式如下:

TRACE("DDDDDDDDDDD");

TRACE("wewe%d",333);

4.然后就会在OUT PUT 中的DEBUG 窗口中看到TRACE 内容了,

调试执行会自动从 BUILD 窗口跳到DEBUG 窗

printf 的功能;该宏仅仅在程序的 DEBUG 版本中 RELEASE 的时候减少代码量。

同样还存在TRACEO , TRACE1 , TRACE2 分别对应0,1,2。。个参数

TRACE信息输出到VC IDE环境的输出窗口(该窗口是你编译项目出错提示的哪个窗口),但仅限于你在VC中运行

你的DEBUG版本的程序。

TRACE信息还可以使用DEBUGVIEW 来捕获到。这种情况下,你不能在VC的IDE环境中运行你的程序,而将

BUILD好的DEBUG版本的程序单独运行,这个时候可以在DEBUGVIEW 的窗口看到DEBUGVIE格式的输出了。

VC中TRACE的用法有以下四种:

TRACE1,就是不带动态参数输出字符串,类似C的Printf(”输出字符串");

TRACE2:中的字符串可以带一个参数输出,类似 C 的Printf("...%d", 变量);

TRACE3 :可以带两个参数输出,类似 C 的Printf("...%d...%f", 变量1,变量2);

TRACE4可以带三个参数输出,类似C的Printf("...%d ,%d,%d",变量1,变量2,变量3);

TRACE宏有点象我们以前在C语言中用的Printf函数,使程序在运行过程中输出一些调试信息,使我们能了解程序

的一些状态。但有一点不同的是:

TRACE宏只有在调试状态下才有所输出,而以前用的Printf函数在任何情况下都有输出。和Printf函数一样,

TRACE函数可以接受多个参数如: int x = 1;

int y = 16;

float z = 32.0;

TRACE( "This is a TRACE statement^");

TRACE( "The value of x is %d\n", x );

TRACE( "x = %d and y = %d\n", x, y );

TRACE( "x = %d and y = %x and z = %f\n", x, y, z );

要注意的是TRACE宏只对Debug版本的工程产生作用,在Release版本的工程中,TRACE宏将被忽略。

三、ASSERT 宏如果你设计了一个函数,该函数需要一个指向文档对象的指针做参数,但是你却错误地用一个视图指针调用了这个函数。这个假的地址将导致视数据的破坏。现在,这种类型的问题可以被完全避免,只要在该函数的开始处实现一个

ASSERT测试,用来检测该指针是否真正指向一个文档对象。一般来讲,编程者在每个函数的开始处均应例行公事地

使用assertion。ASSERT宏将会判断表达式,如果一个表达式为真,执行将继续,否则,程序将显示一条消息并且

暂停,你可以选择忽视这条错误并继续、终止这个程序或者是跳到Debug器中。下面一例演示了如何使用一个

ASSERT宏去验证一个语句。

void foo(char p, int size )

ASSERT( p 匸0 ); // 确认缓冲区的指针是有效的

ASSERT( ( size >= 100 ); // 确认缓冲区至少有100个字节

Do — while 循环将整个 assertion 封装在一个单独的程序块中,使得编译器编译起来很舒畅。 If 语句将求取表达式的

值并且当结果为零时调用 AfxAssertFailedLine() 函数。这个函数将弹出一个对话框,其中提供三个选项 取消、重试 或忽略”当你选取 重试”时,它将返回TRUE 。重试将导致对AfxDebugBreak()

函数的调用,从而激活调试器。

AfxAssertFailedLine() 是一个未正式公布的函数,它的功能就是显示一个消息框。该函数的源代码驻留在

afxasert.cpp

中。函数中的一FILE —和一LINE —语句是处理器标志,它们分别指定了源文件名和当前的行号。

AfxAssertFailedLine() 是一个未正式公布的函数,它的功能就是显示一个消息框。该函数的源代码驻留在

afxasert.c pp

中。函数中的一FILE —和一LINE —语句是处理器标志,它们分别指定了源文件名和当前的行号。

四、VERIFY

因为 assertion 只能在程序的Debug 版本中起作用,在表达式中不可以包含赋值语句、增加语句( + + )或者是减少 语句( ---- ), 因为,这些语句实际改变数据。可有时你可能想要验证一个能动的表达式,使用一个赋值语句。那么 就到了用VERIFY 宏来替代ASSERT 。例如:

voidfoo(char p, int size )

// Do the foo calculation

这些语句不产生任何代码,除非 一DEBUG 处理器标志被设置。Visual C ++只在Debug 版本设置这些标志,而在

Release 版本不定义这些标志。当 一DEBUG 被定义时,两个assertions 将产生如下代码:

//ASSERT ( P 匸 0 );

do{

if( !(p 匸0) && AfxAssertFailedLine(

AfxDebugBreak();

}while(0);

—FILE —, —LINE —))

//ASSERT((size

〉=100);

do{

if(!(size 〉= 100) && AfxAssertFailedLine( — FILE —, — LINE —))

AfxDebugBreak();

}while(0);

char q;

VERIFY(q = p);

//Do the foo calculation

//Do the foo calculation

在Debug 模式下,ASSERT 和VERIFY 是一回事,但是在Release 模式下,VERIFY 宏仍然测试表达式而

assertion 却不起任何作用。可以说,在 Release 模式下,ASSERT 语句被删除了。

请注意,如果你在一个ASSERT 语句中错误地使用了一个能动的表达式,编译器将不做任何警告地忽略它。在

Release 模式下,该表达式就会被无声息地删除掉,这将会导致程序的错误运行。由于 Debug 信息,这类错误将很难被发现。

五、VC 高级调试方法-条件及数据断点的设定 (一)位置断点(LocationBreakpoint

大家最常用的断点是普通的位置断点,在源程序的某一行按 F9就设置了一个位置断点。但对于很多问题,这种朴素

的断点作用有限。譬如下面这段代码:

void CForDebugDlg::OnOK()

for(int i = 0; i < 1000; i++) //A

intk = i * 10 - 2; //B

inttm p = DoSome(i); //D

Trace0("这里要输出的内容”);//在这里可以输出一些有用的信息,你也可以输出I 的值,都是可以的

intj = i / tmp; //E

//其实我们还可以用其他方法调式也是一样的,你可以用 TRACE0宏来输出循环中的每一个结果,我们也可以在

debug 中看见输出的结果,当出现问题时,输出的结果可能就不一样了,我们可以分析一下

题的所在

ASSERT((size

〉=100);

Release 版的程序通常不包含

SendTo(k);

//C

debug 中的结果找出问

执行此函数,程序崩溃于E 行,发现此时tmp 为0,假设tmp 本不应该为0,怎么这个时候为0呢?所以最好能

够跟踪此次循环时DoSome 函数是如何运行的,但由于是在循环体内,如果在 E 行设置断点,可能需要按F5 (GO ) 许多次。这样手要不停的按,很痛苦。使用 VC6断点修饰条件就可以轻易解决此问题。步骤如下。 1 Ctrl+B 打开断点设置框,如下图: Er eakp ein-l Location I Data

Break at:

GAvekb a s e^ForDet

£nter the exfiression to be evaluated;

t

7

P b

= ---------------------------------- R Break when e?c 卩resfiian changes. 、、、

Enter the oumbtr of elemenis to watch in “焉入亘他条F 牛 an array or structure: Breakpoints : 脚耐

ME Enter the number of times to skip before 甘Top 申爭;? Remove AH

Figure 1 设置高级位置断点 2然后选择D 行所在的断点,然后点击condition 按钮,在弹出对话框的最下面一个编辑框中输入一个很大数目,

具体视应用而定,这里1000就够了。 3按F5重新运行程序,程序中断。Ctrl+B 打开断点框,发现此断点后跟随一串说明:...487 times remaining 意思是还剩下487次没有执行,那就是说执行到513( 1000 - 487 )次时候出错的。因此,我们按步骤 2所讲,更 改此断点的skip 次数,将1000改为513。 4再次重新运行程序,程序执行了 513次循环,然后自动停在断点处。这时,我们就可以仔细查看

DoSome 是如何 返回0的。这样,你就避免了手指的痛苦,节省了时间。 再看位置断点其他修饰条件。如 Figure 1 所示,在“ Enter the expression to be evaluated: 下面,可以输入一 些条件,当这些条件满足时,断点才启动。譬如,刚才的程序,我们需要 i 为100时程序停下来, 我们就可以输入在 编辑框中输入“i==100”。 另外,如果在此编辑框中如果只输入变量名称,则变量发生改变时,断点才会启动。这对检测一个变量何时被修改很 方便,特别对一些大程序。

用好位置断点的修饰条件,可以大大方便解决某些问题。

(二)数据断点(DataBreakpoint ) 软件调试过程中,有时会发现一些数据会莫名其妙的被修改掉(如一些数组的越界写导致覆盖了另外的变量),找出 何处代码导致这块内存被更改是一件棘手的事情(如果没有调试器的帮助)。恰当运用数据断点可以快速帮你定位何 时何处这个数据被修改。譬如下面一段程序:

#include "stdafx.h" #include int main(int argc, char* argv[])

charszName1[10];

charszName2[4];

strc py(szName1,"shenzhen");

printf("%s\n",szName1); //A

strc py (szName2,"vckbase"); //B

p rintf("%s\n",szName1);

printf("%s\n",szName2);

return0;

这段程序的输出是

szName1: shenzhen

szName1:ase

szName2:vckbase

首先我给你分析一下为什么会是这样的结果呢!首先你在strc py(szName1,''shenzhen''); 这个地方F9设置一个

断点,然后F5运行程序,这是程序会断到我们设置的断点,如下图

lvalue

3D汕"烫烫绞烫邃烫詐"

I E3 szHan^Z

逗里分配了1 口于字节,地址是D如跑ff?4

逵里分配了&个宇节’地址星0辺DlEEfTCl

I [\ AutD Locals / this /

相关主题