VC++调试技巧学习总结

VC6.0调试方法

有时候,我们编写好一个程序后,希望通过调试来知道变量值的变化情况,下面我和大家分享一下怎么利用VC6.0来查看变量值变化情况。


工具/原料
VC6.0软件、待测试程序
方法/步骤
1
打开你要调试代码的工作空间。
2
按快捷键F5或点击以下图片上标记的图标进入调试模式。


3
打开调试工具条,一般情况下当你按F5键后会自动弹出,如果没有弹出的话,右击工具栏空白处,会弹出下图,选中调试,就会出现调试工具条。


4
接下来,在监视窗口中添加你要监视数据变化的变量。


5
按F11逐语句的调试代码,如果某一语句是一函数,你不希望进入该函数时,F10逐过程来查看,在代码的调试过程中,通过监视窗口查看变量值的变化,从而确定代码是否有问题。


6
如果希望跳出某一函数时,按快捷键Shift+F11,或者直接点击调试工具条上的按钮就可以跳出该函数了。


7
如果只是希望调试某一部分代码的话,可以设置断点来调试,调试方法如上,只是在要调试的代码之间用断点来分开。设置断点时,光标放在你要设置断点的那行,按F9或点击编译微型条上面的类似


手状的按钮即可。
========

VC 6.0 调试技巧(二)

http://blog.csdn.net/dddd0216/article/details/51330163


1. Restart (Ctrl+shift+F5 ): 此debugger功能将从程序的开始(第一有效行)处全速执行,而不是从当前所跟踪的位置开始调试,这时所有变量的当前值都将被丢弃,debugger 会自动停在程序的main()开始


处.这时如果选择Step Over(F10)就可以逐步执行main()函数了.
2. Stop Debugging (Shift+F5 ):此debugger功能将终止(所有)调试,并返回到常规编辑状态. 
3. Break (此功能常常在遇到调用函数的语句时可见 .): 此功能将在调试过程中的debugger当前位置挂起程序的执行,然后就可以在调试状态一修改程序的代码,接着可以用Apply Code Changes(Alt


+F10)来应用修改的代码到正在调试的程序当中.如果,当前(需要,待)可以(从DOS 等窗口)输入值,挂起后将不能再输入.
4. Apply Code Changes (Alt+F10 ):此功能可以在程序正在调试程序过程中应用(挂起)修改后的源代码.如,选择Break功能并修改代码后,只要选择Apply Code Changes(Alt+F10)就能将修改后的代码应


用到正在调试的程序当中.
5. Show Next Statement (Alt+Num* ):此功能将显示程序代码的下一条语句,如果源代码中找不到,则在Disassembly窗口中显示语句. 当在Disassembly窗口中显示时,可以单击Disassembly 返回到源代


码窗口.
6. Step Into (F11 ):此功能可以单步进入到在调试过程中所跟踪的调用函数的语句的函数内部.如,当前语句是"d.Display()", 
选择Step Into(F11)后,Debugger将进入Display()函数内部并停在Display()函数内部的第一条语句上.(此时, 就可以Step Over(F10)对Display()函数进行单步调试了.)
7. Step Over (F10 ):此功能可以单步对所在函数单步调试,如果调试的语句是一个调用函数的语句时, Debugger将全速执行所调用的函数,单步(一步)通过所调用的函数,Debugger停该调用语句的下一条


语句上.
8. Step Out (Shift+F11 ):此功能将使Debugger切换回全速执行到被调用函数结束,并停在该函数调用语句的下一条语句上. 当确定所调用的函数没有问题时可以用这个功能全速执行被调用函数.
9. Run to Cursor (Ctrl+F10 ):此功能将全速执行到包含插入点光标所在的行,可以作为在插入点光标处设置常规断点的一种选择. 注意,当光标处不是一个有效的执行语句时此功能将不起作用.
10. Go (F5 ):此功能将全速执行程序直到遇到一个断点或程序结束,或直到程序暂停等待用户输入. 注意,此功能最能有效的调试循环,常将断点设置在循环体内,重复的按F5全速执行循环体可以测试循环过


程中的产生的变化.
11.Step Into Specific Function:此功能可以可以单步通过程序中的指令,并进入指定的函数调用,此功能对于函数的嵌套层不限.
  
调试常用快捷键
单步进入               F11
 
单步跳过              F10
 
单步跳出              SHIFT+F11
 
运行到光标           CTRL+F10
 
开关断点              F9
 
清除断点              CTRL+SHIFT+F9
 
Breakpoints(断点管理)              CTRL+B 或ALT+F9
 
GO                       F5
 
Compile(编译,生成.obj文件)       CTRL+F7
 
Build(组建,先Compile生成.obj再Link生成.exe)              F7
 
From 《Visual C++ Debugger》
 
From 《visual C++ 6.0开发工具与调试》
1、          如何快速地规范代码缩进格式
选中所需要规范的代码,按shift+F8
2、          如何在Release状态下进行调试
Project->Setting=>ProjectSetting对话框,选择Release状态。C/C++标签中的Category选General,Optimizations选Disable(Debug),
Debut info选Program Database。在Link标签中选中Generate debug info复选框。
 
注:只是一个介乎Debug合Release的中间状态,所有的ASSERT、VERIFY都不起作用,函数调用方式已经是真正的调用,而不查表,
但是这种状态下QuickWatch、调用队列跟踪功能仍然有效,和Debug版一样。
 
3、          Release和Debug有什么不同。
Release版称为发行版,Debug版称为调试版。
Debug中可以单步执行、跟踪等功能,但生成的可执行文件比较大,代码运行速度较慢。Release版运行速度较快,可执行文件较小,
但在其编译条件小无法执行调试功能。
Release的exe文件链接的是标准的MFC DLL(Use MFC in a shared or static dll),比如MFC42.DLL。这些DLL在安装Windows的时候,
已经配置,所以这些程序能够在没有安装Visual C++ 6.0的机器上运行。而Debug版本的exe链接了调试版本的MFC DLL文件,如MFC42D.DLL。
在没有安装Visual C++6.0的机器上不能运行,因为缺MFC42D.DLL等,除非选择use static dll when link。
 
4、          ASSERT和VERIFY有什么区别
ASSERT里面的内容在Release版本中不编译,VERIFY里面的内容仍然翻译,但不再判断真假。所以后者更安全一点。
例如ASSERT(file.Open(strFileName))。
一旦到了Release版本中,这一行就忽略了,file根本就不Open()了,而且没有任何出错的信息。如果用VERIFY()就不会有这个问题。
 
5、          Workspace和Project之间是什么样的关系
每个Workspace可以包括几个project,但只有一个处于Active状态,各个project之间可以有依赖关系,在project的Setting..中可以设定,
比如那个Active状态的project可以依赖于其他的提供其函数调用的静态库。
 
6、          如何在非MFC程序中使用ClassWizard
在工程目录下新建一个空的.RC文件,然后加入到工程中就可以了。
 
7、          如何设置断点
按F9在当前光标处增加一个断点和取消一个断点。
另外,在编辑状态下,按Ctrl+B组合键,弹出断点设置对话框。然后单击【Condition…】按钮弹出设置断点条件的对话框进行设置。
 
8、          在编辑状态下发现成员变量或函数不能显示提示是如何打开显示功能
这似乎是目前这个Visual C++ 6.0版本的一个bug,可按如下步骤使其正常,如再出现,可如法炮制:
(1)             关闭Project
(2)             删除"工程名.ncb"文件
(3)             重新打开工程
 
9、          如何将一个通过ClassWizard生成的类彻底删除
首先在工作区的FileView中选中该类的.h和.cpp文件,按delete删除,然后在文件管理器中将这两个文件删除,再运行ClassWizard,
这时出现是否移走该类的提示,选择remove就可以了。
 
10、     如何将再workspace中消失的类找出来
打开该类对应的头文件,然后将其类名随便改一下,这个时候工作区就会出现新的类,再将这个类改回原来的名字就可以了。
 
11、     如何清除所有的断点
菜单【Edit】->【Breakpoints…】,打开"Breakpoints"对话框,单击【Remove All】按钮即可。
快捷键是"Ctrl + Shift + F8"。
 
12、     如何再ClassWizard中选择未列出的信息
打开"ClassWizard"对话框,然后切换到"Class Info"页面。改变"Message filter",如选择"Window","Message"页面就会出现Window的信息。
 
13、     如何检测程序中的括号是否匹配
把光标移动到需要检测的括号前面,按快捷键"Ctrl + ]"。如果括号匹配正确,光标就跳到匹配的括号处,否则光标不移动,
并且机箱喇叭还会发出一声警告。
 
14、     如何查看一个宏(或变量、函数)的定义
把光标移动到要查看的一个宏上,就比如说最常见的DECLARE_MAP_MESSAGE上按一下F12(或右键菜单中的相关菜单),
如果没有建立浏览文件,就会出现提示对话框,按【确定】按钮,然后就会跳到该宏(或变量、函数)定义的地方。
 
15、     如何添加Lib文件到当前工程
单击菜单【Project】->【Settings…】弹出"Project Setting"对话框,切换到"Link"标签页,在"Object/library modules"处输入Lib文件名称,
不同的Lib之间用空格格开。
 
16、     如何快速删除项目下的Debug文件夹中临时文件
在工作区的FileView视图中选中对应的项目,单击右键弹出菜单,选择【Clean(selection only)】菜单即可。
 
17、     如何快速生成一个现有工程除了工程名外完全相同的新工程。
在新建工程的"New"对话框中选择"Custom Appwizard"项,输入新工程的名字,单击【OK】按钮。出现"Custom AppWizard"项,
输入新工程的名字,单击【OK】按钮。出现"Custom AppWizard-Step 1 of 2"对话框,选择"An existing Project"项,单击【Next】按钮。
出现"Custom AppWizard-Step 2 of 2"对话框,选择现有工程的工程文件名,最后单击【Finish】按钮。编译后就生成一个与现有工程相同
但可以重新取名的工程AppWizard。
现在就可以项用MFC AppWizard一样用这个定制的向导。如果不想用了,可以在Visual C++ 6.0安装目录下Common/MSDev98/Template目录
中删除该Wizard对应的.awx和.pdb文件。
 
18、     如何解决Visual C++ 6.0不正确连接的问题
情景:明明之间改动了一个文件,却要把整个项目全部重新编译链接一次。刚刚链接好,一运行,有提示重新编译链接一次。
这是因为出现了未来文件(修改时间和创建时间比系统时间晚)的缘故。可以这样处理:找到工程文件夹下的debug目录,
将创建和修改时间都比系统时间的文件全部删除,然后再从新"Rebuild All"一次。
 
19、     引起LNK2001的常见错误都有哪些
遇到的LNK2001错误主要为:unresolved external symbol "symbol"
如果链接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误信息。
一般来说,发生错误的原因有两个:一时所引用的函数、变量不存在,拼写不正确或者使用错误;其次可能使用了不同版本的链接库。
一下是可能产生LNK2001错误的原因:
<1>由于编码错误导致的LNK2001错误
1.不相匹配的程序代码或模块定义(.DEF)文件导致LNK2001。例如,如果在C++源文件了内声明了一变量"var1", 
却视图在另一个文件内以变量"var1"访问改变量。
(2)             如果使用的内联函数是在.cpp文件内定义的,而不是在头文件内定义将导致LNK2001错误。
(3)             调用函数是如果所用的参数类型头函数声明是的类型不符将会产生LNK2001错误。
(4)             视图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001错误。
(5)             要注意函数和变量的可公用性,只有全局变量、函数时可公用的。静态函数和静态变量具有相同的使用范围限制。
当试图从文件外部方位任何没有在该文件内声明的静态变量时将导致编译错误或LNK2001错误。
<2>由于编译和联机的设置而造成的LNK2001错误
1.如果编译时使用的时/NOD(/NODERAULTLIB)选项,程序所需要的运行库和MFC时将得到又编译器写入目标文件模块, 
但除非在文件中明确包含这些库名,否则这些库不会北链接进工程文件。这种情况下使用/NOD将导致LNK2001错误
2.如果没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时讲的到 
"unresolved external on _WinMain@16 "的LNK2001错误信息。
3.使用/MD选项编译时,既然所有的运行库都被保留在动态链接库之内,源文件中对"func"的引用, 
在目标文件里即对"__imp__func"的引用。如果试图使用静态库LIBC.LIB或LIBCMT.LIB进行链接,将在__imp__func上发生LNK2001错误。如果不使用/MD选项编译,在使用MSVCxx.LIB链接时也会发


生LNK2001错误。
(4)             使用/ML选项编译时,如用LIBCMT.LIB链接回在_errno上发生LNK2001错误。
(5)             当编译调试版的应用程序时,如果采用发行版模态库进行链接也会产生LNK2001错误;同样,
使用调试版模态库链接发行版应用程序时也会产生相同的错误。
(6)             不同版本的库和编译器的混合使用也能产生问题,因为新版的库里可能包含早先的版本没有的符号和说明。
(7)             在不同的模块中使用内联和非内联的编译选项能够导致LNK2001错误。如果创建C++库时打开了
函数内联(/Ob1或/Ob2),但是在描述该函数的相应头问卷安里却关闭了函数内联(没有inline关键字),
只是将得到错误信息。为避免该问题的发生,应该在相应的头文件中用inline关键字标志为内联函数。
(8)             不正确的/SUBSYSTEM或ENTRY设置也能导致LNK2001错误。
 
20、     如何调试一个没有源码的exe文件调用的dll
在Visual C++ 6.0中,进入"Project Setting"对话框然后选择Debug标签页。通常Visual Studio默认"executable for debug session"为可执行文件名,
但可以将他改成任何你想要的程序。甚至可以指定不同的工作目录以及传递参数到你的程序。这个技术常用来调试Dlls、名字空间扩展、
COM对象和其他从某些EXE以及从第三方的EXE中调用的plug-in程序。
 
21、     Visual C++ 6.0工程中的项目文件都表示什么。
.opt:工程关于开发化境的参数文件。如工具条位置等信息。
.aps(AppStudio File)资源辅助文件,二进制格式,一般不用去管他。
.clw:ClassWizard信息文件,实际上是INI文件格式,又兴趣可以研究一下。有时候ClassWizard出了问题,手工修改CLW文件可以解决。
如果此文件不存在的话,每次用ClassWizard的时候回提示是否重建。
.dsp(DevelopStudio Project):项目文件,文本格式,不过不熟悉的或不要手工修改。
.dsw(DevelopStudio Workspace):是工作区文件,其他特点和.dsp差不多。
.plg:是编译信息文件,编译时的error和warning信息文件(实际上时一个html文件),一般用处不大。在单击菜单【Tool】->【Option】
弹出的对话框里面有个选项可以控制这个文件的生成。
.hpj(Help Project):是生成帮助文件的工程,用microsoft Help Compiler可以处理。
.mdp(Microsoft DevStudio Project):是旧版本的项目文件,如果要打开此文件的话,回提示你是否转换成新的.dsp格式。
.bsc:是用于浏览项目信息的,如果用Source Brower的话旧必须又这个文件。如果不用这个功能的话,可以在Project Options里面去掉
Generate Browse Info File,这样可以加快编译速度。
.map是执行文件的影像信息记录文件,除非对系统底层,这个文件一般用不着。
.pch(Pre-Compiled File):是与编译文件,可以加快编译速度,但是文件非常大。
.pdb(Program Database),记录了程序有关的一些数据和调试信息,在调试的时候可能有用。
.exp:只有在编译DLL的时候才会生成,记录了DLL文件的一些信息,一般也没有用。
.ncb:无编译浏览文件(no compile browser)。当自动完成功能出问题时可以删除此文件。编译工程后回自动生成。
========

VC++一些开发心得与调试技巧

http://www.cnblogs.com/maowang1991/p/3572329.html
     1.如何在Release状态下进行调试
  Project->Setting=>ProjectSetting对话框,选择Release状态。C/C++标签中的Category选General,Optimizations选Disable(Debug),Debut info选Program Database。在Link标签中选中


Generate debug info复选框。
  注:只是一个介乎Debug和Release的中间状态,所有的ASSERT、VERIFY都不起作用,函数调用方式已经是真正的调用,而不查表,但是这种状态下QuickWatch、调用队列跟踪功能仍然有效,


和Debug版一样。


  2. Release和Debug有什么不同
  Release版称为发行版,Debug版称为调试版。
  Debug中可以单步执行、跟踪等功能,但生成的可执行文件比较大,代码运行速度较慢。Release版运行速度较快,可执行文件较小,但在其编译条件下无法执行调试功能。
  Release的exe文件链接的是标准的MFC DLL(Use MFC in a shared or static dll)。这些DLL在安装Windows的时候,已经配置,所以这些程序能够在没有安装Visual C++ 6.0的机器上运行。而


Debug版本的exe链接了调试版本的MFC DLL文件,在没有安装Visual C++6.0的机器上不能运行,因为缺相应的DLL,除非选择use static dll when link。


  3. ASSERT和VERIFY有什么区别
  ASSERT里面的内容在Release版本中不编译,VERIFY里面的内容仍然翻译,但不再判断真假。所以后者更安全一点。
  例如ASSERT(file.Open(strFileName))。
  一旦到了Release版本中,这一行就忽略了,file根本就不Open()了,而且没有任何出错的信息。如果用VERIFY()就不会有这个问题。


  4.Workspace和Project之间是什么样的关系
  每个Workspace可以包括几个project,但只有一个处于Active状态,各个project之间可以有依赖关系,在project的Setting..中可以设定,比如那个Active状态的project可以依赖于其他的提供其


函数调用的静态库。


  5. 如何在非MFC程序中使用ClassWizard
  在工程目录下新建一个空的.RC文件,然后加入到工程中就可以了。


  6.如何设置断点
  按F9在当前光标处增加一个断点和取消一个断点。
  另外,在编辑状态下,按Ctrl+B组合键,弹出断点设置对话框。然后单击【Condition…】按钮弹出设置断点条件的对话框进行设置。


  7.在编辑状态下发现成员变量或函数不能显示提示是如何打开显示功能
  这似乎是目前这个Visual C++ 6.0版本的一个bug,可按如下步骤使其正常,如再出现,可如法炮制:
  (1)关闭Project
  (2)删除“工程名.ncb”文件
  (3)重新打开工程


  8.如何将一个通过ClassWizard生成的类彻底删除
  首先在工作区的FileView中选中该类的.h和.cpp文件,按delete删除,然后在文件管理器中将这两个文件删除,再运行ClassWizard,这时出现是否移走该类的提示,选择remove就可以了。


  9. 如何将在workspace中消失的类找出来
  打开该类对应的头文件,然后将其类名随便改一下,这个时候工作区就会出现新的类,再将这个类改回原来的名字就可以了。


  10. 如何清除所有的断点
  菜单【Edit】->【Breakpoints…】,打开“Breakpoints”对话框,单击【Remove All】按钮即可。快捷键是“Ctrl + Shift + F9”。


  11. 如何再ClassWizard中选择未列出的信息
  打开“ClassWizard”对话框,然后切换到“Class Info”页面。改变“Message filter”,如选择“Window”,“Message”页面就会出现Window的信息。


  12. 如何检测程序中的括号是否匹配
  把光标移动到需要检测的括号前面,按快捷键“Ctrl + ]”。如果括号匹配正确,光标就跳到匹配的括号处,否则光标不移动,并且机箱喇叭还会发出一声警告。


  13. 如何查看一个宏(或变量、函数)的定义
  把光标移动到要查看的一个宏上,就比如说最常见的DECLARE_MAP_MESSAGE上按一下F12(或右键菜单中的相关菜单),如果没有建立浏览文件,就会出现提示对话框,按【确定】按钮,然后就


会跳到该宏(或变量、函数)定义的地方。


  14. 如何添加Lib文件到当前工程
  单击菜单【Project】->【Settings…】弹出“Project Setting”对话框,切换到“Link”标签页,在“Object/library modules”处输入Lib文件名称,不同的Lib之间用空格格开。


  15. 如何快速删除项目下的Debug文件夹中临时文件
  在工作区的FileView视图中选中对应的项目,单击右键弹出菜单,选择【Clean(selection only)】菜单即可。


  16. 如何快速生成一个现有工程除了工程名外完全相同的新工程
  在新建工程的“New”对话框中选择“Custom Appwizard”项,输入新工程的名字,单击【OK】按钮。出现“Custom AppWizard”项,输入新工程的名字,单击【OK】按钮。出现“Custom 


AppWizard-Step 1 of 2”对话框,选择“An existing Project”项,单击【Next】按钮。出现“Custom AppWizard-Step 2 of 2”对话框,选择现有工程的工程文件名,最后单击【Finish】按钮。


编译后就生成一个与现有工程相同但可以重新取名的工程AppWizard。
  现在就可以项用MFC AppWizard一样用这个定制的向导。如果不想用了,可以在Visual C++ 6.0安装目录下Common\MSDev98\Template目录中删除该Wizard对应的.awx和.pdb文件。


  17. 如何解决Visual C++ 6.0不正确连接的问题
  情景:明明改动了一个文件,却要把整个项目全部重新编译链接一次。刚刚链接好,一运行,又提示重新编译链接一次。
  这是因为出现了未来文件(修改时间和创建时间比系统时间晚)的缘故。可以这样处理:找到工程文件夹下的debug目录,将创建和修改时间都比系统时间的文件全部删除,然后再从新“Rebuild All


”一次。


  18. 引起LNK2001的常见错误都有哪些
  遇到的LNK2001错误主要为:unresolved external symbol “symbol”
  如果链接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误信息。
一般来说,发生错误的原因有两个:一是所引用的函数、变量不存在,拼写不正确或者使用错误;其次可能使用了不同版本的链接库。以下是可能产生LNK2001错误的原因:
  <1>由于编码错误导致的LNK2001错误
  (1)不相匹配的程序代码或模块定义(.DEF)文件导致LNK2001。例如,如果在C++源文件了内声明了一变量“var1”,却试图在另一个文件内以变量“var1”访问改变量。
  (2)如果使用的内联函数是在.cpp文件内定义的,而不是在头文件内定义将导致LNK2001错误。
  (3)调用函数时如果所用的参数类型和头函数声明时的类型不符将会产生LNK2001错误。
  (4)试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001错误。
  (5)要注意函数和变量的可公用性,只有全局变量、函数是可公用的。静态函数和静态变量具有相同的使用范围限制。当试图从文件外部方位任何没有在该文件内声明的静态变量时将导致编译错误


或LNK2001错误。
  <2>由于编译和联机的设置而造成的LNK2001错误
  (1)如果编译时使用的是/NOD(/NODERAULTLIB)选项,程序所需要的运行库和MFC时将得到又编译器写入目标文件模块,但除非在文件中明确包含这些库名,否则这些库不会被链接进工程文件。


这种情况下使用/NOD将导致LNK2001错误
  (2)如果没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时将出现“unresolved external on _WinMain@16”的LNK2001错误信息。
  (3)使用/MD选项编译时,既然所有的运行库都被保留在动态链接库之内,源文件中对“func”的引用,在目标文件里即对“__imp__func”的引用。如果试图使用静态库LIBC.LIB或LIBCMT.LIB进


行链接,将在__imp__func上发生LNK2001错误。如果不使用/MD选项编译,在使用MSVCxx.LIB链接时也会发生LNK2001错误。
  (4)使用/ML选项编译时,如用LIBCMT.LIB链接会在_errno上发生LNK2001错误。
  (5)当编译调试版的应用程序时,如果采用发行版模态库进行链接也会产生LNK2001错误;同样,使用调试版模态库链接发行版应用程序时也会产生相同的错误。
  (6)不同版本的库和编译器的混合使用也能产生问题,因为新版的库里可能包含早先的版本没有的符号和说明。
  (7)在不同的模块中使用内联和非内联的编译选项能够导致LNK2001错误。如果创建C++库时打开了函数内联(/Ob1或/Ob2),但是在描述该函数的相应头文件里却关闭了函数内联(没有inline关键字


),只是将得到错误信息。为避免该问题的发生,应该在相应的头文件中用inline关键字标志为内联函数。
  (8)不正确的/SUBSYSTEM或ENTRY设置也能导致LNK2001错误。


  19. 如何调试一个没有源码的exe文件调用的dll
  在Visual C++ 6.0中,进入“Project Setting”对话框然后选择Debug标签页。通常Visual Studio默认“executable for debug session”为可执行文件名,但可以将他改成任何你想要的程序。


甚至可以指定不同的工作目录以及传递参数到你的程序。这个技术常用来调试Dlls、名字空间扩展、COM对象和其他从某些EXE以及从第三方的EXE中调用的plug-in程序。


20. Visual C++ 6.0工程中的项目文件都表示什么
  .opt:工程关于开发环境的参数文件。如工具条位置等信息。
  .aps(AppStudio File)资源辅助文件,二进制格式,一般不用去管它。
  .clw:ClassWizard信息文件,实际上是INI文件格式,有兴趣可以研究一下。有时候ClassWizard出了问题,手工修改CLW文件可以解决。如果此文件不存在的话,每次用ClassWizard的时候回提


示是否重建。
  .dsp(DevelopStudio Project):项目文件,文本格式,不过不熟悉的不要手工修改。
  .dsw(DevelopStudio Workspace):是工作区文件,其他特点和.dsp差不多。
  .plg:是编译信息文件,编译时的error和warning信息文件(实际上是一个html文件),一般用处不大。在单击菜单【Tool】->【Option】弹出的对话框里面有个选项可以控制这个文件的生成。
  .hpj(Help Project):是生成帮助文件的工程,用microsoft Help Compiler可以处理。
  .mdp(Microsoft DevStudio Project):是旧版本的项目文件,如果要打开此文件的话,会提示你是否转换成新的.dsp格式。
  .bsc:是用于浏览项目信息的,如果用Source Brower的话就必须有这个文件。如果不用这个功能的话,可以在Project Options里面去掉Generate Browse Info File,这样可以加快编译速度。
  .map是执行文件的映象信息记录文件,除非对系统底层,这个文件一般用不着。
  .pch(Pre-Compiled File):是与编译文件,可以加快编译速度,但是文件非常大。
  .pdb(Program Database):记录了程序有关的一些数据和调试信息,在调试的时候可能有用。
  .exp:只有在编译DLL的时候才会生成,记录了DLL文件的一些信息,一般也没有用。
  .ncb:无编译浏览文件(no compile browser)。当自动完成功能出问题时可以删除此文件。编译工程后会自动生成。
========

vc调试技巧

http://blog.csdn.net/yaneng/article/details/5660889
VC调试技巧收集整理 
      调试是一个程序员最基本的技能,其重要性甚至超过学习一门语言。不会调试的程序员就意味着他即使会一门语言,却不能编制出任何好的软件。
      这里我简要的根据自己的经验列出调试中比较常用的技巧,希望对大家有用。本文约定,在选择菜单时,通过/表示分级菜单,例如File/Open表示顶级菜单File的子菜单open。        
        
        1 设置
        为了调试一个程序,首先必须使程序中包含调试信息。一般情况下,一个从AppWizard创建的工程中包含的Debug 
      Configuration自动包含调试信息,但是是不是Debug版本并不是程序包含调试信息的决定因素,程序设计者可以在任意的Configuration中增加调试信息,包括Release版本。
        为了增加调试信息,可以按照下述步骤进行: 
        
        a 打开Project settings对话框(可以通过快捷键ALT+F7打开,也可以通过IDE菜单Project/Settings打开) 
        
        b 选择C/C++页,Category中选择general ,则出现一个Debug Info下拉列表框,可供选择的调试信息方式包括: 
         None:
         没有调试信息 
         Line Numbers Only:
         目标文件或者可执行文件中只包含全局和导出符号以及代码行信息,不包含符号调试信息 
         C7 Compatible: 
         目标文件或者可执行文件中包含行号和所有符号调试信息,包括变量名及类型.函数及原型 等 
         Program Database: 
         创建一个程序库(PDB),包括类型信息和符号调试信息。 
         Program Database for Edit and Continue: 
         除了上面的功能外,这个选项允许对代码进行调试过程中的修改和继续执行。
         这个选项同时使#pragma设置的优化功能无效 
        
        c 选择Link页,选中复选框"Generate Debug Info",这个选项将使连接器把调试信息写进可执行文件和DLL
      .如果C/C++页中设置了Program Database以上的选项,则Link 
      incrementally可以选择。选中这个选项,将使程序可以在上一次编译的基础上被编译(即增量编译),而不必每次都从头开始编译。 
   
        2 断点
        断点是调试器设置的一个代码位置。当程序运行到断点时,程序中断执行,回到调试器。断点是 
      最常用的技巧。调试时,只有设置了断点并使程序回到调试器,才能对程序进行在线调试。
        
        设置断点:可以通过下述方法设置一个断点。首先把光标移动到需要设置断点的代码行上,然后 
        按F9快捷键 
        弹出Breakpoints对话框,方法是按快捷键CTRL+B或ALT+F9,或者通过菜单Edit/Breakpoints打开。打开后点击Break 
      at编辑框的右侧的箭头,选择 合适的位置信息。一般情况下,直接选择line 
      xxx就足够了,如果想设置不是当前位置的断点,可以选择Advanced,然后填写函数、行号和可执行文件信息。
        去掉断点:把光标移动到给定断点所在的行,再次按F9就可以取消断点。同前面所述,打开Breakpoints对话框后,也可以按照界面提示去掉断点。
        
        条件断点:可以为断点设置一个条件,这样的断点称为条件断点。对于新加的断点,可以单击Conditions按钮,为断点设置一个表达式。当这个表达式发生改变时,程序就 
      被中断。底下设置包括“观察数组或者结构的元素个数”,似乎可以设置一个指针所指向的内存区的大小,但是我设置一个比较的值但是改动 
      范围之外的内存区似乎也导致断点起效。最后一个设置可以让程序先执行多少次然后才到达断点。
        
        数据断点:数据断点只能在Breakpoints对话框中设置。选择“Data”页,就显示了设置数据断点的对话框。在编辑框中输入一个表达式,当这个 
      表达式的值发生变化时,数据断点就到达。一般情况下,这个表达式应该由运算符和全局变量构成,例如:在编辑框中输入 
      g_bFlag这个全局变量的名字,那么当程序中有g_bFlag= !g_bFlag时,程序就将停在这个语句处。
        
        消息断点:VC也支持对Windows消息进行截获。他有两种方式进行截获:窗口消息处理函数和特定消息中断。在Breakpoints对话框中选择Messages页,就可以设置消息断点。如果在上面那


个对话框中写入消息处理函数的名字,那么 
      每次消息被这个函数处理,断点就到达(我觉得如果采用普通断点在这个函数中截获,效果应该一样)。如果在底下的下拉 
      列表框选择一个消息,则每次这种消息到达,程序就中断。
 
        3 Watch
        VC支持查看变量、表达式和内存的值。所有这些观察都必须是在断点中断的情况下进行。
        观看变量的值最简单,当断点到达时,把光标移动到这个变量上,停留一会就可以看到变量的值。
        VC提供一种被成为Watch的机制来观看变量和表达式的值。在断点状态下,在变量上单击右键,选择Quick Watch, 
      就弹出一个对话框,显示这个变量的值。
        单击Debug工具条上的Watch按钮,就出现一个Watch视图(Watch1,Watch2,Watch3,Watch4),在该视图中输入变量或者表达式,就可以观察 
      变量或者表达式的值。注意:这个表达式不能有副作用,例如++运算符绝对禁止用于这个表达式中,因为这个运算符将修改变量的值,导致 软件的逻辑被破坏。


        4 Memory
        由于指针指向的数组,Watch只能显示第一个元素的值。为了显示数组的后续内容,或者要显示一片内存的内容,可以使用memory功能。在 
      Debug工具条上点memory按钮,就弹出一个对话框,在其中输入地址,就可以显示该地址指向的内存的内容。
    
        5 Varibles
        Debug工具条上的Varibles按钮弹出一个框,显示所有当前执行上下文中可见的变量的值。特别是当前指令涉及的变量,以红色显示。
 
        6 寄存器
        Debug工具条上的Reigsters按钮弹出一个框,显示当前的所有寄存器的值。
  
        7 进程控制
        VC允许被中断的程序继续运行、单步运行和运行到指定光标处,分别对应快捷键F5、F10/F11和CTRL+F10。各个快捷键功能如下: 
        快捷键 说明 
        F5 继续运行 
        F10 单步,如果涉及到子函数,不进入子函数内部 
        F11 单步,如果涉及到子函数,进入子函数内部 
        CTRL+F10 运行到当前光标处。 
  
        8 Call Stack
        调用堆栈反映了当前断点处函数是被那些函数按照什么顺序调用的。单击Debug工具条上的Call stack就显示Call 
      Stack对话框。在CallStack对话框中显示了一个调用系列,最上面的是当前函数,往下依次是调用函数的上级函数。单击这些函数名可以跳到对应的函数中去。
 
        9 其他调试手段
        系统提供一系列特殊的函数或者宏来处理Debug版本相关的信息,如下: 
        
        10 宏名/函数名 说明 
        TRACE 使用方法和printf完全一致,他在output框中输出调试信息 
        ASSERT 它接收一个表达式,如果这个表达式为TRUE,则无动作,否则中断当前程序执行。对于系统中出现这个宏 
      导致的中断,应该认为你的函数调用未能满足系统的调用此函数的前提条件。例如,对于一个还没有创建的窗口调用SetWindowText等。 
        VERIFY 和ASSERT功能类似,所不同的是,在Release版本中,ASSERT不计算输入的表达式的值,而VERIFY计算表达式的值。 
        
        关注:
        一个好的程序员不应该把所有的判断交给编译器和调试器,应该在程序中自己加以程序保护和错误定位,具体措施包括: 
        
         对于所有有返回值的函数,都应该检查返回值,除非你确信这个函数调用绝对不会出错,或者不关心它是否出错。 
         一些函数返回错误,需要用其他函数获得错误的具体信息。例如accept返回INVALID_SOCKET表示accept失败,为了查明 
      具体的失败原因,应该立刻用WSAGetLastError获得错误码,并针对性的解决问题。 
         有些函数通过异常机制抛出错误,应该用TRY-CATCH语句来检查错误 
        程序员对于能处理的错误,应该自己在底层处理,对于不能处理的,应该报告给用户让他们决定怎么处理。如果程序出了异常, 
      却不对返回值和其他机制返回的错误信息进行判断,只能是加大了找错误的难度。 
         另外:VC中要编制程序不应该一开始就写cpp/h文件,而应该首先创建一个合适的工程。因为只有这样,VC才能选择合适的编译、连接 
      选项。对于加入到工程中的cpp文件,应该检查是否在第一行显式的包含stdafx.h头文件,这是Microsoft Visual 
      Studio为了加快编译 速度而设置的预编译头文件。在这个#include 
      "stdafx.h"行前面的所有代码将被忽略,所以其他头文件应该在这一行后面被包含。
         对于.c文件,由于不能包含stdafx.h,因此可以通过Project settings把它的预编译头设置为“不使用”,方法是: 
        弹出Project settings对话框 
        选择C/C++ 
        Category选择Precompilation Header 
        选择不使用预编译头。
      [url]http://www.yzcc.com/yzcc/vv/08475592434.html[/url]


      其他技巧:


      1.在调试状态下怎样查看错误消息(GetLastError())?
      通常可以用GetLastError()得到错误编号然后用FormatMessage(...)得到错误描述。
      这里有一个更直接的办法:在Watch窗口添加@err,hr


      2.怎样知道程序是否有内存泄漏(Memory Leak)?
      在VC开发环境下Press 
      [F5],在调试状态下运行程序,测试有可能出现内存泄漏的操作,关闭程序,在Output窗口查看运行信息.如果出现泄漏,在Output中会有记录。当然,不能完全依靠这种方式来发现程序运行有内存泄漏。


      3.当某一变量满足某种条件时,停止在断点.
      如以下一程序片段:
      2 int iLocation;
      ...
      30 iLocation++
      ...
      要求: 在line30设有断点,并想在iLocation>100 
      本文来源:[url]http://blog.tianya.cn/blogger/post_show.asp?BlogID=237133&PostID=3587659[/url]


   便于调试的代码风格:


不用全局变量
所有变量都要初始化,成员变量在构造函数中初始化
尽量使用const
详尽的注释


VC++编译选项:


总是使用/W4警告级别
在调试版本里总是使用/GZ编译选项,用来发现在Release版本中才有的错误
没有警告的编译:保证在编译后没有任何警告,但是在消除警告前要进行仔细检查


调试方法:


1、使用 Assert(原则:尽量简单)
assert只在debug下生效,release下不会被编译。


例子:
char* strcpy(char* dest,char* source)
{
assert(source!=0);
assert(dest!=0);
char* returnstring = dest;
while((*dest++ = *source++)!= ‘/0’)
{
;
}
return returnstring;

2、防御性的编程


例子:
char* strcpy(char* dest,char* source)
{
if(source == 0)
{
assert(false);
reutrn 0;
}
if(dest == 0)
{
assert(false);
return 0;
}
char* returnstring = dest;
while((*dest++ = *source++)!= ‘/0’)
{
;
}
return returnstring;

3、使用Trace


以下的例子只能在debug中显示,


例子:


a)、TRACECString csTest = “test”;
TRACE(“CString is %s/n”,csTest);
b)、ATLTRACE


c)、afxDump
CTime time = CTime::GetCurrentTime();
#ifdef _DEBUG
afxDump << time << “/n”;
#endif
4、用GetLastError来检测返回值,通过得到错误代码来分析错误原因


5、把错误信息记录到文件中


异常处理


程序设计时一定要考虑到异常如何处理,当错误发生后,不应简单的报告错误并退出程序,应当尽可能的想办法恢复到出错前的状态或者让程序从头开始运行,并且对于某些错误,应该能够容错,即允


许错误的存在,但是程序还是能够正常完成任务。


调试技巧


1、VC++中F5进行调试运行


a)、在output Debug窗口中可以看到用TRACE打印的信息
b)、 Call Stack窗口中能看到程序的调用堆栈


2、当Debug版本运行时发生崩溃,选择retry进行调试,通过看Call Stack分析出错的位置及原因
3、使用映射文件调试


a)、创建映射文件:Project settings中link项,选中Generate mapfile,输出程序代码地址:/MAPINFO: 
LINES,得到引出序号:/MAPINFO: EXPORTS。
b)、程序发布时,应该把所有模块的映射文件都存档。
c)、查看映射文件:见” 通过崩溃地址找出源代码的出错行”文件。


4、可以调试的Release版本


Project settings中C++项的Debug Info选择为Program Database,Link项的Debug中选择Debug 
Info和Microsoft format。


5、查看API的错误码,在watch窗口输入@err可以查看或者@err,hr,其中”,hr”表示错误码的说明。
6、Set Next Statement:该功能可以直接跳转到指定的代码行执行,一般用来测试异常处理的代码。
7、调试内存变量的变化:当内存发生变化时停下来。


常见错误


1、在函数返回的时候程序崩溃的原因


a)、写自动变量越界
b)、函数原型不匹配


2、MFC


a)、使用错误的函数原型处理用户定义消息


正确的函数原型为:
afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);
3、谨慎使用TerminateThread:使用TerminateThread会造成资源泄漏,不到万不得已,不要使用。


4、使用_beginthreadex,不要使用Create Thread来常见线程。


WindowS 调试


1.Windows跟踪语句:


(1)TRACE(_T(“Warning (FunctionName):Object %s not found./n”),objectName);


在输出的调试窗口会输出结果。跟踪信息输出到输出窗口output window中。[调试版本中使用]


(2)C++的C运行时刻库函数跟踪语句
    ANSI C 运行时刻库函数没有跟踪语句,但是VC++的C运行时刻库函数有。可使用_RPTn或_RPTFn调试报告宏,但是你必须在程序中引用crtdbg.h,并利用C运行时刻函数库链接:
   _RPT0(reportType,format);
   _RPT1(reportType,format,arg1);
   _RPT2(reportType,format,arg1,arg2);


   _RPTF0(reportType,format);
   _RPTF1(reportType,format,arg1);
   _RPTF2(reportType,format,arg1,arg2);
   例子:
          int a =1000,b=2000;
         int *p =&a;
         int *q = &b;
       _RPTF2(_CRT_WARN,"%x ,%x",p,q); //直接在outputwindow中输出
       _RPTF2(_CRT_ERROR,"%x ,%x",p,q);   //弹出ERROR对话框
       _RPTF2( _CRT_ASSERT,"%x ,%x",p,q);   //弹出AEESRT对话框
reportType:_CRT_WARN _CRT_ERROR _CRT_ASSERT
其中_CRT_WARN用于跟踪语句,_RPTFn宏报告了源码文件名和调用这些宏的行号。[调试版本中使用]
可以使用_CrtSetReportMode函数改变默认输出设置,(比如输出到调试器输出窗口,文件,消息框中),_CrtSetReportFile可以指定将报告输出到哪个文件中。


(3)MFC中的跟踪语句
       区别:使用TRACE宏时,需要使用_T宏来格式化参数以正确解决Unicode的校正,反之,在TRACEn类型的宏中,不必使用_T宏。
       TRACE(_T("ssss/n"));
       TRACE2("%d r %d l/n",1,2);


(4)异常和返回值


C++程序中可以使用异常和返回值来返回状态信息。C语言返回一个函数的状态的最好方法就是它的返回值
Try
{
//code may fail
}
Catch
{
//handle the failure
}
只有在抛出异常的时候会有开销!Catch块有一些开销,但是try块有很少的开销!只能在调试版中处理异常,并弹出MessageBox,发布版不处理异常,为的就是优化。
     try
     {
       int *pInt = 0;
       *pInt =42;
     }
     catch(...)
     {
       MessageBox(_T("Exception was caught!"),_T("Exception test"),MB_OK);   
     }
      (5)ANSI C++ 运行时刻函数库跟踪
具体有:C语言的stderr和C++语言的clog流,在Windows程序中没有任何效果!


(6)OutputDebugString (_T(“trace   debug info!/n”));[调试版本中使用]
       如果只想在调试版本中使用OutputDebugString,可以使用下面得宏来实现:
#ifdef   _DEBUG
#define OutputTraceString(text)   OutputDebugString(text)
#else
#define OutputTraceString(text)   ((void) (0))
#endif


使用AfxOutputDebugString
AfxOutputDebugString宏使用和OutputDebugString一样的语法。


7.使用CObiect::Dump
CObject类有一个转储(dump)虚拟函数,继承于它的所有子类函数都可以重载这个函数,输出它们的值。
例 1 -2:用下列语句输出CObject派生类pObject的值。afxDump是预定义的全局变量CDumpContext,注意 CDumpContext对最一般的内建数据类型及CObject的指针和引用支持插入操作符(<<)


。有几个CObject派生的类也有定 义的插入操作符,CPoint,CSize,CRect,CString,CTime和CTimeSpan。
#if _DEBUG
AfxDump(pObiect);
pObject->Dump(afxDump);
afxDump<<pObject;
#endif


例1-3:
afxDump<<_T(“Warning:This object doesn’t seem right:/n”)<<pObject;
8.使用AfxDump
AfxDump是MFC中相当于cerr流的跟踪语句,所以你可以直接向它输出跟踪消息。
TRACE宏由afxDump实现,afxDump由AfxOutputDebugString实现。而AfxOutputDebugString在调试版中由_RPT0宏实现。可以使用下面的方法将afxDump重定向。
#ifdef _DEBUG
CFile dumpFile; //必须为全局变量
     dumpFile.Open(_T("dump.log"),CFile::modeWrite|CFile::modeCreate);
     afxDump.m_pFile = &dumpFile;
#endif
9.使用AfxDumpStack
可以使用AfxDumpStack函数输出一个调用栈:
void AFXAPI AfxDumpStack(DWORD dwTarget = AFX_STACK_DUMP_TARGET_DEFAULT);
参 数:dwTarget决定在调试和发布版本中输出到什么地方,可以输出到TRACE宏,OutputDebugString或到剪贴板。如果使用 AFX_STACK_DUMP_TARGET_TRACE,含义是在调试版中输出到


TRACE宏,而在发布版本中没有输出!如果你希望在发布版本中输出, 可使用AFX_STACK_DUMP_TARGET_ODS选项,而且必须在路径中有Imagehlp.dll文件。在project& 


#61664;settings&#61664;Link&#61664;Category&#61664;Debug Both formats。 
10.ATL跟踪语句 最基本的类型是AtlTrace函数:
inline void_cdecl AtlTrace(LPCTSTR format……);
ATLTRACE (format……);


和MFC TRACE宏一样,它使用一个512字节固定大小的缓冲区,如果它的参数需要一个大于512字节的文本缓冲区,会导致一个出错的断言。实际上,它是使用API函数OutputDebugString实现的,


因此它的输出不能改变到其他目标。
ATL跟踪语句的另一个选择AtlTrace2函数:
Inline void _cedecl AtlTrace2(DWORD category,UINT level,LPCTSTR format,…);
ATLTRACE(category,level,format);
该 函数增加了一个参数跟踪类别(category)(例如,atlTraceCOM,atlTraceWindowing和 atlTraceControl)和一个参数严格级别。类别值是位掩码,ATL自身使用介于0-2的级别值,0级指最严格的级别


。 和AtlTrace函数类似,AtlTrace2函数只能用在调试版本中!
11.VC++消息Pragma
Pagama是一个编译时的跟踪语句,可用来警告在预处理过程中发现的潜在的编连(build)问题
12.处理长字符串:[例如处理SQL语句]
(1)MFC下[只能调试版]
TRACE(longString); //assert if _tcslen(longString)>511,最大是512
#ifdef _DEBUG
afxDump<<longString;//dosen’t assert for long strings 不需要判断
#endif
(2)ATL下[只能调试版]
ATLTRACE(longString); //assert if _tcslen(longString)>511,最大是512
#ifdef _DEBUG
OutputDebugString(longString); //dosen’t assert for long strings 不需要判断
#endif
13.处理大量的跟踪输出。
如果跟踪消息数据产生的速度超过输出窗口处理的速度,那么消息会塞满缓冲区,数据会丢失。
简单方法:在输出大量数据的代码段,例如对象转储函数时候,调用 Sleep API函数。例如:Sleep(100).


 调试
1.当错误发生得时候,调用GetLastError()得到相应得错误码
错误码得位域有固定的格式,,在C:/Program Files/Microsoft Visual Studio/VC98/Include/Winerror.h中有详细的说明:
//
//   Values are 32 bit values layed out as follows:
//
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//   +---+-+-+-----------------------+-------------------------------+
//   |Sev|C|R|     Facility           |               Code             |
//   +---+-+-+-----------------------+-------------------------------+
//
//       Sev - is the severity code       安全代码
//
//           00 – Success           0-安全   
//           01 – Informational     1-信息
//           10 – Warning         2-警告
//           11 – Error             3-错误
//       C - is the Customer code flag 
客户代码:0-Microsoft定义的,1-客户定义的
//       R - is a reserved bit 保留位必须是0  
//       Facility - is the facility code工具-Microsoft 定义的
//       Code - is the facility's status code 工具状态代码-Microsoft或客户定义
   工具:更好的查看错误代码的方法,Tools-》Error Lookup;在VC++调试器的watch窗口中输入@ERR监视GetLastError的返回数值,ERR是调试器用来显示最新错误码的一个虚拟寄 存器。还可


以用 @ERR,hr将错误码转换为文本格式
   
   技巧:在调试中,按F11键,Alt+8显示反汇编窗口,在Edit菜单中选择Go To命令,在GoTo对话框的Go to what中选择Address选项,在Enter address expression中输入导致崩溃的地址。


创 建映射文件的方法:Project&#61664;Settings&#61664;Link&#61664;Generate mapfile.即可在工程的Debug文件下看到。映射文件里面所有的公共符号都使用混合名字。可使用VC++的名字


解析工具(Undname)将混合 名字转换到原始名字。你可以在“开始”&#61664;”运行”&#61664;”cmd”&#61664;输入
C:/Documents and Settings/zhangzhongping>cd C:/Program Files/Microsoft Visual Studio/Common/Tools
输入:
C:/ProgramFiles/MicrosoftVisualStudio/Common/Tools>Undname ?RandException@@YGXHHHH@Z
Microsoft(R) Windows NT(R) Operating System
UNDNAME Version 5.00.1768.1Copyright (C) Microsoft Corp. 1981-1998
输出:
>> ?RandException@@YGXHHHH@Z == RandException


当输入-f时,显示整个函数的原型!查看映射文件的时候,若出现重载函数,名字解析工具很有用!
输入:
C:/ProgramFiles/MicrosoftVisualStudio/Common/Tools>Undname-f ?RandException@@YGXHHHH@Z
Microsoft(R) Windows NT(R) Operating System
UNDNAME Version 5.00.1768.1Copyright (C) Microsoft Corp. 1981-1998
输出:
>> ?RandException@@YGXHHHH@Z == void __stdcall RandException(int,int,int,int)


使用MFC和ATL的DEF文件:


MFC的DEF文件在
C:/ProgramFiles/MicrosoftVisual Studio/VC98/MFC/SRC/Intel目录下。
ATL的DEF文件在
C:/Program Files/Microsoft Visual Studio/VC98/ATL/SRC目录下。
如 果用户运行自己的程序出现:The ordinal 6880 could not be located in the dynamic link Library MFC42.dll信息。你可查看MFC42.DEF中对应的6880号函数:? 


ScreenToClient@CWnd@@QBEXPAUtagRECT@@@Z @ 6880 NONAME.然后可以用名字解析工具解析混合名字如下:
输入:
C:/Program Files/Microsoft Visual Studio/Common/Tools>Undname -f ?ScreenToClient@CWnd@@QBEXPAUtagRECT@@@Z @ 6880 NONAME
Microsoft(R) Windows NT(R) Operating System
UNDNAME Version 5.00.1768.1Copyright (C) Microsoft Corp. 1981-1998
输出:
>> ?ScreenToClient@CWnd@@QBEXPAUtagRECT@@@Z == public: void __thiscall CWnd::ScreenToClient(struct tagRECT *)const
>> @ == @
>> 6880 == 6880
>> NONAME == NONAME
使用依赖关系浏览工具:
VC++依赖关系浏览工具(COMMON/TOOLS/Depends.exe)


 内存泄漏的调试
在VC中我们使用_CrtDumpMemoryLeaks()来检测内存泄漏。
例子:
void CTRACEDlg::OnButton1() 
{
     int *pLeak = new int; //故意造成内存泄漏
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
     //delete pLeak;
     //pLeak = NULL;
     _CrtDumpMemoryLeaks();//调用此函数在output window的Debug窗口中显示内存泄漏的地址的数据。
    
}
Debug窗口中显示:
Detected memory leaks!
Dumping objects ->
C:/ProgramFiles/MicrosoftVisualStudio/MyProjects/TRACE/TRACEDlg.cpp(181) : {89} normal block at 0x004213B0, 4 bytes long.
Data: <     > CD CD CD CD 
Object dump complete.




注意:0xCD表示已经分配的数据
       0xDD表示已经释放的数据
       0xFD表示被保护的数据


断言
1.断言的特征:
(1)发现运行时刻错误(用户输入错误,资源分配错误,文件系统错误,硬件错误或其他类型错误)
(2)断言中的布尔表达式显示的是某个对象或者状态的有效性,而不是正确性
(3)断言在条件编译后只存在调试版本里面,特别是,断言只在_DEBUG符号定义后,才能编译!
(4)断言不能包含程序代码,也不能有副作用,不能修改程序变量,也比能调用修改程序变量的函数
(5)断言只是给程序员提供有用信息的
2.断言的类型
(1)ANSI C断言
Void assert(expression)     包含在assert.h头文件中(最好不用assert)
原因:*当文件名太长的化,对话框显示的路径将会被截至掉!
*函数是由ANSI NDEBUG函数驱动的,如果定义了NDEBUG后,断言就被取消!


如果要启用JIT调试(Just-in-time),在Tools&#61664;Options&#61664;Debug
中选择Just-in-time debugging,默认也会勾选上OLE RPC debugging
单击“重试(R)”就会显示出错误所在的标记行。


(2)C运行时刻函数库断言
_ASSERT(Boolean Expression)   (crtdbg.h)[不用]


_ASSERTE(Boolean Expression)   (crtdbg.h)[经常用这个]


_ASSERTE宏更能给出更多简洁,有用的信息,显示了断言!


(3)MFC库中的断言


ASSERT(Boolean expression) ASSERT宏和_ASSERT宏显示的消息框相同。VERIFY(Boolean expression) VERIFY 中的BOOL表达式在发布版本中被保留了下来。它简化了对返回值的判断!


CString str;


VERIFY(str.LoadString(IDS_STRING));//不要用VERIFY宏


ASSERT_VALID宏,被用来决定一个指向CObject派生类的对象的指针是否有效。ASSERT(pObjectDerivedFromCObject);主要是在使用CObject派生类对象之前调用,检查对象的有效性。


ASSERT_KINDOF(className,pObjectDerivedFromCObject);


ASSERT_POINTER(pointer,pointerType);


ASSERT_NULL_OR_POINTER(pointer,pointerType);


AfxlsValidAddress(const void*memoryAddress,UINT memoryBytes,BOOL isWriteable = TRUE);


BOOL AfxlsValidString (LPCSTR string, int stringLength = -1);


(4)ATL断言


如果你使用ATL,crtdbg.h就包含在atlbase.h中。在任何ATL代码中,ATLASSERT才是你的选择,在atldef.h中你会发现ATLASSERT是_ASSERT的一个别名。


优点:在ATL程序中使用ATLASSERT可以让你使用自己的断言。


(5)考虑使用_ASSERTE(FALSE)来简化防御性的编程和断言的结合,要想得到描述性的断言消息,考虑使用_ASSERTE(“Problem description.”==0).


_ASSERTE("This is the object requires the MM_TEXT mapping mode" == 0);


If (!expression)
{


//handle error


_ASSERT(FALSE);



}


If(FAILED(SomeFunction()))
{
//handle error


_ASSERT(FALSE)
}


(6)考虑使用_CrtSetReportMode和_CrtSetReportFile


========
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页