编程心得

1. 代码调试

1.1 代码调试的方法

1.1.1 Debug版本的调试

 a)通过设置断点,单步运行进行排错。

 b)通过调试,然后按下“alt+7”弹出Call Stack,然后对照其中指向的函数,来判断出错的地方,然后进行逐步调试。


 

 c)网络摘录

     在VC中当整个工程较大时,软件时常为出现在DEBUG状态下能运行而在RELEASE状态下无法运行的情况。由于开发者通常在DEBUG状态下开发软件,所以这种情况时常是在我们辛苦工作一两个月后,满怀信心的准备将软件发行时发生。为了避免无谓的损失,我们最好进行以下的检查:

1、时常测试软件的两种版本。

2、不要轻易将问题归结为DEBUG/RELEASE问题,除非你已经充分对两种版本进行了测试。

3、预处理的不同,也有可能引起这样的问题。
出现问题的一种可能性是在不同版本的编译间定义了不同的预处理标记。请对你的DEBUG版本的软件试一下以下改动:  

在 "Project   Setting(ALT-F7) "   中的C/C++项中设置目录(category)为 "General ",并且改动 "_DEBUG "定义为 "NDEBUG ".  
设置目录为 "Preprocessor "并且添加定义 "_DEBUG到 "Undefined   Symbols "输入框.  
选择Rebuild   ALL,重新编译.
如果经过编译的程序产生了问题,请对代码进行如下改动:  
将ASSERT()   改为   VERIFY()。因为ASSERT中的内容在Release版本中不被编译。  
找出定义在 "#ifdef   _DEBUG "中的代码,如果在RELEASE版本中需要这些代码请将他们移到定义外。  
查找TRACE(...)中代码,因为这些代码在RELEASE中也不被编译。
所以请认真检查那些在RELEASE中需要的代码是否并没有被编译。  

4、变量的初始化所带来的不同,在不同的系统,或是在DEBUG/RELEASE版本间都存在这样的差异,所以请对变量进行初始化。  

5、是否在编译时已经有了警告?请将警告级别设置为3或4,然后保证在编译时没有警告出现.  

6、是否改动了资源文件.  

7、此外对RELEASE版本的软件也可以进行调试,请做如下改动:  

在 "Project   Settings "   中   "C++/C   "   项目下设置   "category "   为   "General "   并且将 "Debug   Info "设置为   "Program   Database ".  
在 "Link "项目下选中 "Generate   Debug   Info "检查框。  
"Rebuild   All "
如此做法会产生的一些限制:  
无法获得在MFC   DLL中的变量的值。  
必须对该软件所使用的所有DLL工程都进行改动。  


另:
MS   BUG:MS的一份技术文档中表明,在VC5中对于DLL的 "Maximize   Speed "优化选项并未被完全支持,因此这将会引起内存错误并导致程序崩溃。


 

 

1.1.2 Realease版本调试


 

 

a)网上摘录

 

在软件产品的测试过程中,以及发布之后,程序可能会由于一般保护错(GPF)而崩溃。即程序中访问了禁止访问的内存。这时,程序一般情况下无法继续运行,只能结束。
   
在安装了调试器(比如VC)的系统中,会弹出一个错误对话框,显示类似:
    “0x12345678”指令引用的”0x000000123”内存。
    该内存不能为”written(read)”
    终止单击确定,调试单击取消。

  没有调试器的系统中一般会出现一个Dr. watson窗口,内容类似。
   
    通常,我们遇到这个问题时只能大致地从程序运行(上下文)情况来粗略推断错误,但实际上有更好的解决办法。

    在开发过程中,编译release版本的程序(包括EXE、DLL、OCX等二进制程序)时,要建立相关的mapfile,即映像文件。方法如下(VC):
(1)     选择release版本;
(2)     Project settings => C/C++ => Debug Info,选
        “Line Number Only”;
(3)     Project settings => link => 选中 “Generate mapfile”;
(4)     Project settings => link => Project Option中,输入 :
        /mapinfo:lines

这样,编译后就会生成一个*.map的文本文件,其中包含了release版本程序的相关信息。

当程序出现GPF时,记下指令地址,然后可以在map文件中的Rva+Base 段查找相关的信息。

    比如:H1接口程序,出错指令为0x0040d7a0,在map文件中,可发现:

        0001:0000c730 ?RefreshDevList@@YGIPAX@Z 0040d730 f   FFServer.obj
   
其中 0040d730是小于0040d7a0的最大地址,则可初步断定是在RefreshDevList函数中出的问题。下一步是定位出错代码在源程序中的行数,mapfile中包含了相关信息。定位方法是先计算偏移量,公式为:

        (crash address) - (preferred load address) - 0x1000

其中(preferred load address)在mapfile首部可以找到。然后,在mapfile中的相关源程序代码行信息段中搜索即可。

在没有mapfile,比如编译时未添加相关选项的情况下,可以用反汇编工具,如Win32Dasm将出错的程序反汇编,找到相关指令并分析。

有时,出错指令地址并不在程序的mapfile中,比如:0x77fcc665。
这一般是在出错程序调用的系统DLL中,比如msvcrt.dll、ntdll.dll等。可以用一个小工具CrashFinder来查找。 0x77fcc665查找的结果是RtlSizeHeap + 000007EA,ntdll.dll。同时,还可以启动调试器(如VC),查看call stack等信息,找到出错指令的上下文。尽量正确能在mapfile中定位。

在《Debugging Applications》一书中有详细的说明。

总之,希望开发者和测试者能注意以下几点:

(1)     发行版(release)的程序,包括DLL、OCX,一定要输出map file;
(2)     map file与相关的程序的版本对应关系一定要认真记录,避免混淆;
(3)     release版程序出现GPF时不要轻易结束,要详细记录下当时的信息,最简单的方法就是进行一下屏幕拷贝。
(4)     在 NT/2000/XP 下,可以通过查看系统日志来获取程序崩溃信息。

原文来自:http://www.cnblogs.com/xxrl/archive/2008/05/06/1185319.html


 b)自己调试VC程序的经验

    第一种方式:使用afxmessagebox函数,在可能出错的位置放置该函数,通过运行过程中是否会弹出该对话框,来判断其代码出错的地方。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值