VC下Debug和Release区别 程序员
最近写代码过程当中,发现 Debug 下运行正常,Release 下就会出现问题,百思不得其解,而Release 下又没法进行调试,因而只能采用printf方式逐步定位到问题所在处,才发现原来是给定的一个数组未初始化,致使后面处理异常。网上查找了些资料,在这 罗列汇总下,作为备忘~
1、Debug 和 Release 的区别
Debug 一般称为调试版本,它包含调试信息,而且不做任何优化,便于程序员调试程序。Release 称为发布版本,它每每是进行了各类优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
Debug 和 Release 的真正区别,在于一组编译选项。
Debug 版本
参数 含义
/MDd /MLd 或 /MTd 使用 Debug runtime library(调试版本的运行时刻函数库)
/Od 关闭优化开关
/D "_DEBUG" 至关于 #define _DEBUG,打开编译调试代码开关(主要针对assert函数)
/ZI
建立 Edit and continue(编辑继续)数据库,这样在调试过程当中若是修改了源代码不需从新编译
GZ 能够帮助捕获内存错误 数据库
Release 版本 参数含义
/MD /ML 或 /MT 使用发布版本的运行时刻函数库
/O1 或 /O2 优化开关,使程序最小或最快
/D "NDEBUG" 关闭条件编译调试代码开关(即不编译assert函数)
/GF 合并重复的字符串,并将字符串常量放到只读内存,防止被修改 编程
Debug 和 Release 并无本质的界限,他们只是一组编译选项的集合,编译器只是按照预约的选项行动。
1. 变量。
你们都知道,debug跟release在初始化变量时所作的操做是不一样的,debug是将每一个字节位都赋成0xcc(注1),而release的赋值近 似于随机(我想是直接从内存中分配的,没有初始化过)。这样就明确了,若是你的程序中的某个变量没被初始化就被引用,就颇有可能出现异常:用做控制变量将 致使流程导向不一致;用做数组下标将会使程序崩溃;更加多是形成其余变量的不许确而引发其余的错误。因此在声明变量后立刻对其初始化一个默认的值是最简 单有效的办法,不然项目大了你找都没地方找。代码存在错误在debug方式下可能会忽略而不被察觉到,如debug方式下数组越界也大多不会出错,在 release中就暴露出来了,这个找起来就比较难了:( 仍是本身多加注意吧
呵呵,就是我犯的问题~~
2. 自定义消息的消息参数。
MFC为咱们提供了很好的消息机制,更增长了自定义消息,好处我就不用多说了。这也存在debug跟release的问题吗?答案是确定的。在自定义消息 的函数体声明时,时常会看到这样的写法:afx_msg LRESULT OnMessageOwn(); Debug状况下通常不会有任何问题,而当你在Release下且多线程或进程间使用了消息传递时就会致使无效句柄之类的错误。致使这个错误直接缘由是消 息体的参数没有添加,即应该写成:afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam); (注2)
3. release模式下不出错,但debug模式下报错。
这种状况下大多也是由于代码书写不正确引发的,查看MFC的源码,能够发现好多ASSERT的语句(断言),这个宏只是在debug模式下才有效,那么就 清楚了,release版不报错是忽略了错误而不是没有错误,这可能存在很大的隐患,由于是Debug模式下,比较方便调试,好好的检查本身的代码,再此 就很少说了。
4. ASSERT, VERIFY, TRACE..........调试宏
这种状况很容易解释。举个例子:请在VC下输入ASSERT而后选中按F12跳到宏定义的地方,这里你就可以发现Debug中ASSERT要执行 AfxAssertFailedLine,而Release下的宏定义却为"#define ASSERT(f) ((void)0)"。因此注意在这些调试宏的语句不要用程序相关变量如i++写操做的语句。VERIFY是个例外,"#define VERIFY(f) ((void)(f))",即执行,这里的做用就很少追究了,有兴趣可本身研究:)。 数组
总结:
Debug与Release不一样的问题在刚开始编写代码时会常常发生,99%是由于你的代码书写错误而致使的,因此不要动不动就说系统问题或编译器问题, 努力找找本身的缘由才是根本。我从前就经常遇到这状况,经历过一次次的教训后我就开始注意了,如今我所写过的代码我已经很久没遇到这种问题了。下面是几个 避免的方面,即便没有这种问题也应注意一下:
1. 注意变量的初始化,尤为是指针变量,数组变量的初始化(很大的状况下另做考虑了)。
2. 自定义消息及其余声明的标准写法
3. 使用调试宏时使用后最好注释掉
4. 尽可能使用try - catch(...)
5. 尽可能使用模块,不但表达清楚并且方便调试。
注1:
debug版初始化成0xcc是由于0xcc在x86下是一条int 3单步中断指令,这样程序若是跑飞了遇到0xcc就会停下来,这和单片机编程时通常将没用的代码空间填入jmp 0000语句是同样地转贴于:计算机二级考试_考试大【责编:drfcy 纠错】
[VC]DEBUG和RELEASE2007年08月26日 星期日 下午 04:33 I. 内存分配问题
1. 变量未初始化。下面的程序在debug中运行的很好。
thing * search(thing * something)
BOOL found;
for(int i = 0; i < whatever.GetSize(); i++)
{
if(whatever[i]->field == something->field)
{ /* found it */
found = TRUE;
break;
} /* found it */
}
if(found)
return whatever[i];
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版的内存分配方式是不一样的 。若是你在DEBUG版中申请 ele 为 6*sizeof(DWORD)=24bytes,实际上分配给你的是32bytes(debug版以32bytes为单位分配), 而在release版,分配给你的就是24bytes(release版以8bytes为单位),因此在debug版中若是你写ele[6],可能不会有 什么问题,而在release版中,就有ACCESS VIOLATE。
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型,不然Debug会过,而Release出错
IV. 内存分配
保证数据建立和清除的统一性:若是一个DLL提供一个可以建立数据的函数,那么这个DLL同时应该提供一个函数销毁这些数据。数据的建立和清除应该在同一个层次上。
V. DLL的灾难
人们将不一样版本DLL混合形成的不一致性形象的称为 “动态链接库的地狱“(DLL Hell) ,甚至微软本身也这么说
http://msdn.microsoft.com/library/techart/dlldanger1.htm
)。
若是你的程序使用你本身的DLL时请注意:
1. 不能将debug和release版的DLL混合在一块儿使用。debug都是debug版,release版都是release版。
解决办法是将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)。编译器的优化可能致使许多意想不到的错误,请参
http://www.pgh.net/~newcomer/debug_release.htm
1. 此外对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"优化选项并未被彻底支持,所以这将会引发内存错误并致使程序崩溃。
2.
http://www.sysinternals.com/
有 一个程序DebugView,用来捕捉OutputDebugString的输出,运行起来后(估计是自设为system debugger)就能够观看全部程序的OutputDebugString的输出。此后,你能够脱离VC来运行你的程序并观看调试信息。
3. 有一个叫Gimpel Lint的静态代码检查工具,听说比较好用
http://www.gimpel.com/
不过要化$的。