VC中TRACE+ASSERT+VERIFY之用法
- 格式:doc
- 大小:54.50 KB
- 文档页数:8
Vs2008开发环境下调试vc++程序入门一、菜单栏中和调试有关的各菜单选项图1-11、Breakpoints显示程序中所有已加的断点。
2、Start Debugging 开始调试程序,如果程序中没有断点,则一直运行完毕,如果程序中设置有断点,则动行至断点。
3、Attach to Process 附加另一个进程进行调试,此进程可以是其它可执行文件,如果有源程序,可调入源程式调式,如无源程序,对此进程的汇编代码进行调试。
4、Toggle BreakPoint 在一行代码处设置断点,也可直接在一行代码前面的灰条处点一鼠标左键。
即可设置断点,如图1-1左侧小红点就是断点。
再次左键点一下即可取消断点。
5、Step Over进入单步调试,或者快捷键F10。
单步调试是一行行的向前运行,遇到函数不进入函数体内;而另一个快捷键F11也是单步调试,但是遇到函数会进入函数体内运行。
也可以用组合键CTRL+F10运行到光标指定点。
6、Delete All BreakPoints 取消所有的断点7、Disable All BreakPoints 禁用所有的断点,但不取消。
再次点一下菜单命令可恢复。
二、各种调试和变量窗口图2-11、最上面显示的是目前所处的进程和线程名2、左边黄色箭头指明现在调试运行到此处3、右边是调试变量窗口,有三个子窗口Autos窗口,Locals窗口,Watch1窗口,这三个窗口中前二个自动显示黄色箭头运行处的本地变量内容。
而Watch1中可手工输入变量名,系统会自动列出变量的值。
Value栏中的内容是可以修改的,比如图2-1中的循环计数变量m_dwSpinCount值是4000,如果我们调试时进入这个循环,要手工运行4000次,才能退出循环,这太麻烦,此时,可以直接鼠标左键点变量窗口中4000这个值,修改变量值为0次。
继续单步调试程序,退出循环。
当然你也可以在循环外面加一个断点,直接按F5跳出循环到断点处。
了解调试,首先要知道"断点"这个概念.断点就是程序运行中可能会中断的地方,方便开发者在程序运行的过程中查看程序当前的运行状态,比如变量的值,函数的返回值等等.究竟怎么使用断点呢?1.调试快捷键F9——在当前光标所在的行下断点,如果当前行已经有断点,则取消断点.F5——调试状态运行程序,程序执行到有断点的地方会停下来.F10——单步执行程序.F11——和F10的区别是,如果当前执行语句是函数调用,则会进入函数里面.CTRL+F10——运行到光标所在行.SHIFT+F11——跳出当前所在函数.特别说明:a.有的地方不能下断点.比如空行,基本类型定义语句(不初始化),等等非执行语句.比如int i; // 此行不能下断点字串7int j = 0; // 这里可以下CString str; // 这里可以下int k = Max(i, j); // 这里可以下b.不是所有断点都会(断).比如下断点的语句在程序里面没有被执行.c.此外,ALT+F9还可以下条件断点,不过这个不常用,有兴趣的可以自己研究:)2.如何调试Release版的程序?有些程序在debug下运行的很好,但在release下却总是失败,默认情况下release是不能调试的.怎么解决呢?其实"debug"和"release"都只是一个代号而已,各自对应一组不同的编译选项.在release的默认设置下,ALT+F7 ,调出工程设置对话框,切换到link选项卡,勾选"Generate debug info",然后再切换到C/C++选项卡,在"Optimizations"里面选"Disable(Debug)",在下面的"Debug info"里面选"Program Database for Edit and Continue".然后点OK保存设置,重新编译程序,下断点即可.3.上面两点已经能应付很多种情况了,但是有时候即使在debug下也不能下断点,我以前也曾经遇到过这种问题,一个调了4层的dll,就是不能下断点.其实还除了上面的方法,还有一种最底层的实现技术:使用汇编.细心的人可能会发现,有时候在调试状态下当程序出现异常的时候,光标会指向汇编代码,而这个代码就是int 3,这其实是一个中断.在你的代码的任意地方加上__asm{int 3};用debug编译,然后直接运行程序.当程序执行到上述代码的时候,就会出现一个框,告诉你说一大堆信息,说程序错了,下面有"调试"、"终止"、"忽略",不用理,点调试就可以进入跟踪了。
VC程序调试VC程序调试调试是一个程序员最基本的技能,其重要性甚至超过学习一门语言。
不会调试的程序员就意味着他即使会一门语言,却不能编制出任何好的软件。
一、VC程序调试方法 VC的调试功能:首先,再次强调要用Go命令运行一个将要调试的程序;如果要中止调试状态下的运行程序可以点击Stop Debugging命令,还可以通过Break选项以可恢复方式中断调试程序的运行流程(用Restart选项可以重新开始运行程序);Step Into选项表示每次只执行一行语句(单步执行),但如果当前代码是调用一个函数,那么Step Into表示进入该函数,全部函数语句执行完后返回,而Step Over则是跳出这个函数;Step To Cursor 选项表示程序将执行到光标所在的可执行语句行上;在调试多线程程序时,可以在线程函数或主应用程序线程中设置断点,还可以用Break选项结束线程后用Threads选项查看运行线程列表,也可以选择悬挂和恢复每个线程;在设置断点后,在VC "查看"菜单的"调试窗口"中可以查看变量、内存、调用堆栈、寄存器以及反汇编语句。
在程序中设置断点的方法是,点击要设置的代码行并点击设置代码的工具栏按钮,会出现在代码行最左边的一个小黑点即是断点标志,这时再选Go 程序会在执行到端点处停下来,如果要继续执行可以再选Go。
通过选择VC"工具"菜单下的"源浏览器"可以生成一个.BSC文件,使用浏览器可以从中发现多种信息:程序中任何一个变量、函数、类或宏在何处定义及引用;可以列出所有声明的函数类、变量、宏;可以发现调用一个指定函数的所有函数;可以找到一个指定类的派生来源或者它派生出哪些类。
在使用微软程序开发库MSDN时,我们会发现其中的VC示例经常采用看似多余的ASSERT语句,其作用就是使程序具有"维护"性。
VC之TRACE ASSERT VERIFY用法一、TRACE宏当选择了Debug目标,并且afxTraceEnabled变量被置为TRUE时,TRACE宏也就随之被激活了。
但在程序的Release版本中,它们是被完全禁止的。
下面是一个典型的TRACE 语句:int nCount =9;CString strDesc("total");TRACE("Count =%d,Description =%s\n",nCount,strDesc);可以看到,TRACE语句的工作方式有点像C语言中的printf语句,TRACE宏参数的个数是可变的,因此使用起来非常容易。
如果查看MFC的源代码,你根本找不到TRACE宏,而只能看到TRACE0、TRACE1、TRACE2和TRACE3宏,它们的参数分别为0、1、2、3。
个人总结用法如下:1.在MFC中加入TRACE语句2.在TOOLS->MFC TRACER中选择“ENABLE TRACING”点击OK3.进行调试运行,GO(F5)(特别注意:不是执行‘!’以前之所以不能看到TRACE内容,是因为不是调试执行,而是‘!’了,切记,切记)4.然后就会在OUTPUT中的DEBUG窗口中看到TRACE内容了,调试执行会自动从BUILD窗口跳到DEBUG窗口,在那里就看到TRACE的内容了以下是找的TRACE的详细介绍:TRACE宏对于VC下程序调试来说是很有用的东西,有着类似printf的功能;该宏仅仅在程序的DEBUG版本中出现,当RELEASE的时候该宏就完全消息了,从而帮助你调式也在RELEASE的时候减少代码量。
使用非常简单,格式如下:TRACE("DDDDDDDDDDD");TRACE("wewe%d",333);同样还存在TRACE0,TRACE1,TRACE2。
分别对应0,1,2。
如果你没有用过甚至听过ASSERT或者TRACE调式宏,那么在很大程度上,你可以忽略这篇文章。
不再扯不相关的东西,我们直入主题好了。
1.TRACE1.1.TRACE的宏定义同样的,我们先从TRACE的宏定义开始研究,TRACE被定义在AFX.H中。
但是我在这个H 文件查找时,并没有发现TRACE被#define成某个函数。
虽然你会发现类似的下面两行代码:#define TRACE __noop///////////////////////////////////#define TRACE ATLTRACE但是,ATL的宏定义并不是我们要找的,而__noop,如果你翻过MSDN会发现这个Keyword 的作用仅仅是忽略被包含的函数及不对参数进行评估(具体请看A附录)。
那么,TRACE到底是如何被使用的呢?机缘巧合之下(这个……),我在TRACE的宏定义附近发现了下面的代码:inline void AFX_CDECL AfxTrace(...) { } // Look at here!#define TRACE __noop#define TRACE0(sz)#define TRACE1(sz, p1)#define TRACE2(sz, p1, p2)#define TRACE3(sz, p1, p2, p3)关注那个AfxTrace。
如果说我们前面找到的都不是真正的TRACE的话,那么,这个AfxTrace 就非常可能是我们要找的,而且,他还是个inline函数!于是,我以“AfxTrace”为关键字Google,果然找到了一些信息。
在以前的AFX.H文件中,存在类似下面的代码:#ifdef _DEBUGvoid AFX_CDECL AfxTrace(LPCTSTR lpszFormat, ...);#define TRACE ::AfxTrace#else#define TRACE 1 ? (void)0 : ::AfxTrace#endif很明显,我们可以看到,TRACE被定义成了AfxTrace。
Visual Studio中的debug和release版本的区别Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
Debug 和Release 的真正秘密,在于一组编译选项。
下面列出了分别针对二者的选项(当然除此之外还有其他一些,如/Fd /Fo,但区别并不重要,通常他们也不会引起Release 版错误,在此不讨论)Debug 版本参数含义/MDd /MLd或/MTd使用Debug runtime library (调试版本的运行时刻函数库)/Od 关闭优化开关/D "_DEBUG" 相当于#define _DEBUG,打开编译调试代码开关(主要针对assert函数) /ZI 创建Edit and continue(编辑继续)数据库,这样在调试过程中如果修改了源代码不需重新编译/GZ 可以帮助捕获内存错误/Gm打开最小化重链接开关,减少链接时间Release 版本参数含义/MD /ML 或/MT 使用发布版本的运行时刻函数库/O1 或/O2 优化开关,使程序最小或最快/D "NDEBUG" 关闭条件编译调试代码开关(即不编译assert函数)/GF 合并重复的字符串,并将字符串常量放到只读内存,防止被修改实际上,Debug 和Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。
事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。
哪些情况下Release 版会出错有了上面的介绍,我们再来逐个对照这些选项看看Release 版错误是怎样产生的1、Runtime Library:链接哪种运行时刻函数库通常只对程序的性能产生影响。
调试版本的Runtime Library 包含了调试信息,并采用了一些保护机制以帮助发现错误,因此性能不如发布版本。
单元测试verify用法以下是 9 条关于单元测试中 verify 用法的内容:1. 嘿,你知道吗?在单元测试里,verify 那可是超级重要的家伙呀!就好像你在冒险中寻找宝藏的关键钥匙一样。
比如说,你想验证某个计算结果是不是等于 5,那你就可以用 verify 来确认呀!2. 哇塞,单元测试中的verify 用法简直绝了!这就好比是一个精准的法官,对结果严格把关。
举个例子嘛,你写了个函数要返回一个特定值,用 verify 去检查它是不是真的返回了那个对的数。
3. 哎呀呀,verify 在单元测试里的作用可不容小觑啊!它就像一个忠诚的卫士,守护着正确结果呢!比如说当你的程序应该输出“Hello”时,就用verify 来看看是不是真的输出啦!4. 嘿,你真的得好好了解下单元测试里 verify 的强大魔力!它就跟一个神奇的放大镜一样,能找出那些微小的错误。
像检查一个数组的长度是不是符合预期,verify 就派上大用场啦!5. 哇哦,单元测试的 verify 可太有意思了!和找隐藏宝藏一样让人兴奋。
就好比你要确定一个变量在经过一系列操作后是不是变成了你期望的值,这时候就要靠 verify 啦!6. 哈哈,单元测试中的 verify 难道不是神一样的存在吗?它就像一束光,照亮正确的道路呀!比如说,你的程序应该打印出特定格式的日志,那用verify 去瞅瞅是不是真这样。
7. 哎哟喂,真得重视单元测试里verify 的用法呀!它就像你的贴心小助手,关键时刻从不掉链子。
比如在验证一个对象的属性值时,verify 就能准确发现对不对呢!8. 天哪,单元测试的 verify 这玩意儿太酷啦!像个超级侦探,不放过任何蛛丝马迹。
你想检查一个流程执行后是不是达到了特定状态,用 verify 呀!9. 单元测试中的 verify 是如此关键呀!那简直就是你的秘密武器。
比如说你想验证某个功能是不是正常运行,不用想,肯定用 verify 呀!我觉得呀,要是不好好利用 verify 来做单元测试,那可真是太可惜啦!。
assert c++用法
assert在C++中是一个宏定义,用于检查代码中的假设是否成立。
当assert检测到假设不成立时,程序将终止执行,并输出错误消息。
assert的用法如下所示:
1. #include <cassert>
2. assert(expression);
其中,expression是一个需要被检查的逻辑表达式,如果表达
式为false,则assert会输出错误消息,终止程序的执行。
assert的使用场景包括:
1. 检查函数参数是否合法;
2. 检查函数返回值是否符合预期;
3. 检查程序中的逻辑错误;
4. 检查特定条件是否成立,如数组索引是否越界等。
在编写代码时,使用assert可以有效地帮助程序员发现和修复
错误,提高代码的健壮性和可维护性。
但是,在生产环境中,assert 会影响程序的性能和稳定性,因此在发布代码前应该删除所有的assert语句。
- 1 -。
VS中Debu g模式和Re lease模式的区别 .一、Debug 和 Release编译方式的本质区别Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
Debug 和 Release的真正秘密,在于一组编译选项。
下面列出了分别针对二者的选项(当然除此之外还有其他一些,如/Fd /Fo,但区别并不重要,通常他们也不会引起Release版错误,在此不讨论)Debug 版本:/MDd /MLd 或 /MTd 使用 Debug runtime library(调试版本的运行时刻函数库)/Od 关闭优化开关/D "_DEBUG"相当于 #define_DEBUG,打开编译调试代码开关(主要针对assert函数)/ZI 创建 Edit and continu e(编辑继续)数据库,这样在调试过程中如果修改了源代码不需重新编译/GZ 可以帮助捕获内存错误/Gm 打开最小化重链接开关,减少链接时间Release版本:/MD /ML 或 /MT 使用发布版本的运行时刻函数库/O1 或 /O2 优化开关,使程序最小或最快/D "NDEBUG"关闭条件编译调试代码开关(即不编译ass ert函数)/GF 合并重复的字符串,并将字符串常量放到只读内存,防止被修改实际上,Debug 和 Release并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。
事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。
二、哪些情况下 Release版会出错有了上面的介绍,我们再来逐个对照这些选项看看 Release版错误是怎样产生的1. Runtime Library:链接哪种运行时刻函数库通常只对程序的性能产生影响。
VC之TRACE ASSERT VERIFY用法一、TRACE宏当选择了Debug目标,并且afxTraceEnabled变量被置为TRUE时,TRACE宏也就随之被激活了。
但在程序的Release版本中,它们是被完全禁止的。
下面是一个典型的TRACE 语句:int nCount =9;CString strDesc("total");TRACE("Count =%d,Description =%s\n",nCount,strDesc);可以看到,TRACE语句的工作方式有点像C语言中的printf语句,TRACE宏参数的个数是可变的,因此使用起来非常容易。
如果查看MFC的源代码,你根本找不到TRACE宏,而只能看到TRACE0、TRACE1、TRACE2和TRACE3宏,它们的参数分别为0、1、2、3。
个人总结用法如下:1.在MFC中加入TRACE语句2.在TOOLS->MFC TRACER中选择“ENABLE TRACING”点击OK3.进行调试运行,GO(F5)(特别注意:不是执行‘!’以前之所以不能看到TRACE内容,是因为不是调试执行,而是‘!’了,切记,切记)4.然后就会在OUTPUT中的DEBUG窗口中看到TRACE内容了,调试执行会自动从BUILD窗口跳到DEBUG窗口,在那里就看到TRACE的内容了以下是找的TRACE的详细介绍:TRACE宏对于VC下程序调试来说是很有用的东西,有着类似printf的功能;该宏仅仅在程序的DEBUG版本中出现,当RELEASE的时候该宏就完全消息了,从而帮助你调式也在RELEASE的时候减少代码量。
使用非常简单,格式如下:TRACE("DDDDDDDDDDD");TRACE("wewe%d",333);同样还存在TRACE0,TRACE1,TRACE2。
分别对应0,1,2。
个参数TRACE信息输出到VC IDE环境的输出窗口(该窗口是你编译项目出错提示的哪个窗口),但仅限于你在VC中运行你的DEBUG版本的程序。
TRACE信息还可以使用DEBUGVIEW来捕获到。
这种情况下,你不能在VC的IDE环境中运行你的程序,而将BUILD好的DEBUG版本的程序单独运行,这个时候可以在DEBUGVIEW 的窗口看到DEBUGVIE格式的输出了。
VC中TRACE的用法有以下四种:1:TRACE0 就是不带动态参数输出字符串,类似C的printf("输出字符串");2:TRACE1 中的字符串可以带一个参数输出,类似C的printf("...%d",变量);3:TRACE2 可以带两个参数输出,类似C的printf("...%d...%f",变量1,变量2);4:TRACE3 可以带三个参数输出,类似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\n" );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 the foo calculation}这些语句不产生任何代码,除非—DEBUG处理器标志被设置。
Visual C++只在Debug版本设置这些标志,而在Release版本不定义这些标志。
当—DEBUG被定义时,两个assertions 将产生如下代码://ASSERT( p != 0 );do{if( !(p != 0) && AfxAssertFailedLine(—FILE—,—LINE—) )AfxDebugBreak();}while(0);//ASSERT((size 〉= 100);do{if(!(size 〉= 100) &&AfxAssertFailedLine(—FILE—,—LINE—))AfxDebugBreak();}while(0);do-while循环将整个assertion封装在一个单独的程序块中,使得编译器编译起来很舒畅。
if语句将求取表达式的值并且当结果为零时调用AfxAssertFailedLine()函数。
这个函数将弹出一个对话框,其中提供三个选项“取消、重试或忽略”,当你选取“重试”时,它将返回TRUE。
重试将导致对AfxDebugBreak()函数的调用,从而激活调试器。
do-while循环将整个assertion封装在一个单独的程序块中,使得编译器编译起来很舒畅。
If语句将求取表达式的值并且当结果为零时调用AfxAssertFailedLine()函数。
这个函数将弹出一个对话框,其中提供三个选项“取消、重试或忽略”,当你选取“重试”时,它将返回TRUE。
重试将导致对AfxDebugBreak()函数的调用,从而激活调试器。
AfxAssertFailedLine()是一个未正式公布的函数,它的功能就是显示一个消息框。
该函数的源代码驻留在afxasert.cpp中。
函数中的—FILE—和—LINE—语句是处理器标志,它们分别指定了源文件名和当前的行号。
三、VERIFY 宏因为assertion只能在程序的Debug版本中起作用,在表达式中不可以包含赋值语句、增加语句(++)或者是减少语句(--),因为,这些语句实际改变数据。
可有时你可能想要验证一个能动的表达式,使用一个赋值语句。
那么就到了用VERIFY宏来替代ASSERT。
例如:void foo(char p, int size ){char q;VERIFY(q = p);ASSERT((size 〉= 100);// Do the foo calculation// Do the foo calculation}在Debug模式下,ASSERT和VERIFY是一回事,但是在Release模式下,VERIFY宏仍然测试表达式而assertion却不起任何作用。
可以说,在Release模式下,ASSERT语句被删除了。
请注意,如果你在一个ASSERT语句中错误地使用了一个能动的表达式,编译器将不做任何警告地忽略它。
在Release模式下,该表达式就会被无声息地删除掉,这将会导致程序的错误运行。
由于Release版的程序通常不包含Debug信息,这类错误将很难被发现。
1、ASSERT与VERIFY宏在Debug模式下作用基本一致,二者都对表达式的值进行计算,如果值为非0,则什么事也不做;如果值为0,则输出诊断信息。
2、ASSERT与VERIFY宏在Release模式下效果完全不一样。
ASSERT不计算表达式的值,也不会输出诊断信息;VERIFY计算表达式的值,但不管值为0还是非0都不会输出诊断信息。
断言(assertion)用带断言信息(程序, 模块, assertion行)的对话框执行. 对话框有3个按钮: "Break", "Repeat" ("Debug"), and "Continue" ("Ignore"). "Break" 结束程序, "Continue" 忽略断言, 最有用的是"Repeat"按钮. 按下它在断言的地方打开源代码编辑器. 在这里你可以测试所有的变量值并明白哪里出了问题。
例如:ASSERT(pPointer);ASSERT(n>0 && n<100);ASSERT(0);ASSERT在执行简单验证时很有用,但对于C++对象,特别是由CObject派生的对象,则有更好的方法ASSERT_VALID来实现类似操作。
作为一般规则,我们应在开始使用每一个对象之前检查数据讹误,ASSERT_VALID宏使得对CObject的派生类实现该操作非常简单。
例如:ASSERT_VALID(this);ASSERT_VALID(pView);补充说明:VERIFY()VERIFY()和 ASSERT()很相似,区别在于在 Release 版本中它仍然有效(译者注:原作者在这里没有讲清楚,VERIFY()不会打印说明,只是会对参数表达式求值)。
TRACE()TRACE()基本上就是函数 printf()的一个复制品,唯一的区别是它把结果输出到调试窗口。
在 Release 版本中,它也是无效的。
一般是用TRACE0(),TRACE1(),TRACE2()…而不用TRACE()。
这三个宏在 Release 版本中都不会产生任何实质性的影响,它们是否起作用取决于是否定义了预定义了宏 _DEBUG。
这是对 Microsoft Visual C++ 而言,在其它的编译器中可能其它不同的宏。