转载:
Debug版本包括调试信息,所以要比Release版本大很多(可能大数百K至数M)。至于是否需要DLL支持,主要看你采用的编译选项。如果是基于ATL的,则Debug和Release版本对DLL的要求差不多。如果采用的编译选项为使用MFC动态库,则需要MFC42D.DLL 一、Debug 和 Release 编译方式的本质区别 Debug 通常称为调试版本 Debug 和 Release 的真正秘密,在于一组编译选项 Debug 版本: /MDd /MLd 或 /MTd 使用Debug runtime library /Od 关闭优化开关 /D "_DEBUG"相当于#define _DEBUG /ZI 创建Edit and continue /GZ 可以帮助捕获内存错误 /Gm 打开最小化重链接开关,减少链接时间 Release 版本: /MD /ML 或 /MT 使用发布版本的运行时刻函数库 /O1 或 /O2 优化开关,使程序最小或最快 /D "NDEBUG" 关闭条件编译调试代码开关(即不编译assert函数) /GF 合并重复的字符串 实际上,Debug 和 Release 并没有本质的界限 二、哪些情况下 Release 版会出错 有了上面的介绍,我们再来逐个对照这些选项看看 Release 版错误是怎样产生的 1. Runtime Library 2. 优化:这是造成错误的主要原因,因为关闭优化时源程序基本上是直接翻译的,而打开优化后编译器会作出一系列假设。这类错误主要有以下几种: (1)帧指针(Frame Pointer)省略(简称FPO): ● MFC 消息响应函数书写错误。正确的应为 afx_msg LRESULT OnMessageOwn(WPARAM wparam,LPARAM lparam); ON_MESSAGE宏 #undef ON_MESSAGE #define ON_MESSAGE(message,memberFxn){ message,0,0,0,AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(static_cast<LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM,LPARAM)>(&memberFxn)}, (2) volatile型变量 (3)变量优化 ●非法访问,包括数组越界、指针错误等。例如 void fn(void) { int i; i = 1; int a[4]; { int j; j = 1; } a[-1] = 1;//当然错误不会这么明显,例如下标是变量 a[4] = 1; } j虽然在数组越界时已出了作用域,但其空间并未收回,因而i和j就会掩盖越界 3. _DEBUG 与NDEBUG ANSI C 断言void assert(int expression); C Runtime Lib 断言 _ASSERT(booleanExpression); _ASSERTE(booleanExpression); MFC断言 ASSERT(booleanExpression); VERIFY(booleanExpression); ASSERT_VALID(pObject); ASSERT_KINDOF(classname,pobject); ATL断言 ATLASSERT(booleanExpression); 此外,TRACE()宏 所有这些断言都只在Debug版中才被编译,而在Release版中被忽略。唯一的例外是 顺便值得一提的是 VERIFY()宏 4. /GZ (1) 初始化内存和变量 (2)通过函数指针调用函数时,会通过检查栈指针验证函数调用的匹配性。(防止原形不匹配) (3)函数返回前检查栈指针,确认未被修改。(防止越界访问和原形不匹配,与第二项合在一起可大致模拟帧指针省略FPO 通常/GZ选项会造成Debug版出错而Release版正常的现象 除此之外,/Gm /GF ---------------------------------------------------- 一、"Debug是调试版本,包括的程序信息更多" 二、一般发布release的方法除了hzh_shat(水)所说的之外,还可以project->Set Active Config,选中release版本。此后,按F5或F7编译所得的结果就是release版本。 VC下关于debug和release的不同的讨论 在使用VC开发软件的过程中,正当要享受那种兴奋的时候突然发现:release与debug运行结果不一致 1. 变量。 大家都知道,debug跟release在初始化变量时所做的操作是不同的 2. 自定义消息的消息参数。 MFC为我们提供了很好的消息机制,更增加了自定义消息 3. release模式下不出错,但debug模式下报错。 这种情况下大多也是因为代码书写不正确引起的,查看MFC的源码,可以发现好多ASSERT的语句(断言),这个宏只是在debug模式下才有效,那么就清楚了,release版不报错是忽略了错误而不是没有错误,这可能存在很大的隐患,因为是Debug模式下,比较方便调试,好好的检查自己的代码,再此就不多说了。 4. ASSERT, VERIFY, TRACE……….调试宏 这种情况很容易解释。举个例子:请在VC下输入ASSERT然后选中按F12跳到宏定义的地方,这里你就能够发现Debug中ASSERT要执行AfxAssertFailedLine 总结: Debug与Release不同的 1. 注意变量的初始化,尤其是指针变量,数组变量的初始化 2. 自定义消息及其他声明的标准写法 3. 使用调试宏时使用后最好注释掉 4. 尽量使用try - catch(…) 5. 尽量使用模块,不但表达清楚而且方便调试。 注1: afc(afc) 网友提供: debug版初始化成0xcc是因为0xcc在x86下是一条int 3单步中断指令 注2: 不知大家有没有遇到过这种情况,具体原因我也不太清楚,是不是调用时按着默认的参数多分配了WPARAM+LPARAM的空间而破坏了应用程序的内存空间?还请高手来补充。 NightWolf 网友提供:我遇见过,好像是在函数调用的时候参数入栈的问题。因为MFC的消息使用宏写的,所以如果定义了OnMessage()的函数,编译能够通过,但是调用一次后,堆栈指针发生了偏移。然后就。。。 --------------------------------------------------------- DEBUG和RELEASE 版本差异及调试相关问题: I.内存分配问题 1.变量未初始化。下面的程序在debug中运行的很好。 thing * search(thing * something) BOOL found; for(int i = 0; i < whatever.GetSize(); i++) { if(whatever { /* found it */ found = TRUE; break; } /* found it */ } if(found) return whatever else return NULL; 而在release中却不行,因为debug中会自动给变量初始化found=FALSE,而在release版中则不会。所以尽可能的给变量、类或结构初始化。 2.数据溢出的问题 如:char buffer[10]; int counter; lstrcpy(buffer, "abcdefghik"); 在debug版中buffer的NULL覆盖了counter的高位,但是除非counter>16M,什么问题也没有。但是在release版中,counter可能被放在寄存器中,这样NULL就覆盖了buffer下面的空间,可能就是函数的返回地址,这将导致ACCESS ERROR。 3.DEBUG版和RELEASE版的内存分配方式是不同的 II. ASSERT和VERIFY 1. ASSERT在Release版本中是不会被编译的。 ASSERT宏是这样定义的 #ifdef _DEBUG #define ASSERT(x) if( (x) == 0) report_assert_failure() #else #define ASSERT(x) #endif 实际上复杂一些 比如 ASSERT(pNewObj = new CMyClass); pNewObj->MyFunction(); 这种时候Release版本中的pNewObj不会分配到空间 所以执行到下一个语句的时候程序会报该程序执行了非法操作的错误。这时可以用VERIFY : #ifdef _DEBUG #define VERIFY(x) if( (x) == 0) report_assert_failure() #else #define VERIFY(x) (x) #endif 这样的话,代码在release版中就可以执行了。 III.参数问题: 自定义消息的处理函数,必须定义如下: afx_msg LRESULT OnMyMessage(WPARAM, LPARAM); 返回值必须是HRESULT型 IV.内存分配 保证数据创建和清除的统一性:如果一个DLL提供一个能够创建数据的函数,那么这个DLL同时应该提供一个函数销毁这些数据。数据的创建和清除应该在同一个层次上。 V.DLL的灾难 人们将不同版本DLL混合造成的不一致性形象的称为 “动态连接库的地狱 如果你的程序使用你自己的DLL时请注意: 1.不能将debug和release版的DLL混合在一起使用 解决办法是将debug和release的程序分别放在主程序的debug和release目录下 2.千万不要以为静态连接库 VI.RELEASE板中的调试 : 1.将ASSERT() 改为 VERIFY() 。找出定义在"#ifdef _DEBUG"中的代码,如果在RELEASE版本中需要这些代码请将他们移到定义外。查找TRACE(...)中代码,因为这些代码在RELEASE中也不被编译。 请认真检查那些在RELEASE中需要的代码是否并没有被编译。 2.变量的初始化所带来的不同,在不同的系统,或是在DEBUG/RELEASE版本间都存在这样的差异,所以请对变量进行初始化 3.是否在编译时已经有了警告?请将警告级别设置为3或4 VII.将Project Settings" 中 "C++/C " 项目下优化选项改为Disbale(Debug)。编译器的优化可能导致许多意想不到的错误 1.此外对RELEASE版本的软件也可以进行调试 在"Project Settings" 中 "C++/C " 项目下设置 "category" 为 "General" 并且将"Debug Info"设置为 "Program Database"。 在"Link"项目下选中"Generate Debug Info"检查框。 "Rebuild All" 如此做法会产生的一些限制: 无法获得在MFC DLL中的变量的值。 必须对该软件所使用的所有DLL工程都进行改动。 另: MS BUG 2. 3.有一个叫Gimpel Lint的静态代码检查工具,据说比较好用。 参考文献: 1) 2) |
Debug和Release有什么区别?
最新推荐文章于 2024-03-24 11:30:18 发布