`
isiqi
  • 浏览: 16587783 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Debug和Release有什么区别

阅读更多

Debug版本包括调试信息,所以要比Release版本大很多(可能大数百K至数M)。至于是否需要DLL支持,主要看你采用的编译选项。如果是基于ATL的,则Debug和Release版本对DLL的要求差不多。如果采用的编译选项为使用MFC动态库,则需要MFC42D.DLL等库支持,而Release版本需要MFC42.DLL支持。Release Build不对源代码进行调试,不考虑MFC的诊断宏,使用的是MFC Release库,编译十对应用程序的速度进行优化,而Debug Build则正好相反,它允许对源代码进行调试,可以定义和使用MFC的诊断宏,采用MFC Debug库,对速度没有优化。


一、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 包含了调试信息,并采用了一些保护机制以帮助发现错误,因此性能不如发布版本。编译器提供的 Runtime Library 通常很稳定,不会造成 Release 版错误;倒是由于 Debug 的 Runtime Library 加强了对错误的检测,如堆内存分配,有时会出现 Debug 有错但 Release 正常的现象。应当指出的是,如果 Debug 有错,即使 Release 正常,程序肯定是有 Bug 的,只不过可能是 Release 版的某次运行没有表现出来而已。

2. 优化:这是造成错误的主要原因,因为关闭优化时源程序基本上是直接翻译的,而打开优化后编译器会作出一系列假设。这类错误主要有以下几种:

(1) 帧指针(Frame Pointer)省略(简称 FPO ):在函数调用过程中,所有调用信息(返回地址、参数)以及自动变量都是放在栈中的。若函数的声明与实现不同(参数、返回值、调用方式),就会产生错误————但 Debug 方式下,栈的访问通过 EBP 寄存器保存的地址实现,如果没有发生数组越界之类的错误(或是越界“不多”),函数通常能正常执行;Release 方式下,优化会省略 EBP 栈基址指针,这样通过一个全局指针访问栈就会造成返回地址错误是程序崩溃。C++ 的强类型特性能检查出大多数这样的错误,但如果用了强制类型转换,就不行了。你可以在 Release 版本中强制加入 /Oy- 编译选项来关掉帧指针省略,以确定是否此类错误。此类错误通常有:

● MFC 消息响应函数书写错误。正确的应为
afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam);
ON_MESSAGE 宏包含强制类型转换。防止这种错误的方法之一是重定义 ON_MESSAGE 宏,把下列代码加到 stdafx.h 中(在#include "afxwin.h"之后),函数原形错误时编译会报错
#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 型变量:volatile 告诉编译器该变量可能被程序之外的未知方式修改(如系统、其他进程和线程)。优化程序为了使程序性能提高,常把一些变量放在寄存器中(类似于 register 关键字),而其他进程只能对该变量所在的内存进行修改,而寄存器中的值没变。如果你的程序是多线程的,或者你发现某个变量的值与预期的不符而你确信已正确的设置了,则很可能遇到这样的问题。这种错误有时会表现为程序在最快优化出错而最小优化正常。把你认为可疑的变量加上 volatile 试试。

(3) 变量优化:优化程序会根据变量的使用情况优化变量。例如,函数中有一个未被使用的变量,在 Debug 版中它有可能掩盖一个数组越界,而在 Release 版中,这个变量很可能被优化调,此时数组越界会破坏栈中有用的数据。当然,实际的情况会比这复杂得多。与此有关的错误有:
● 非法访问,包括数组越界、指针错误等。例如
void fn(void)
{
int i;
i = 1;
int a[4];
{
int j;
j = 1;
}
a[-1] = 1;//当然错误不会这么明显,例如下标是变量
a[4] = 1;
}
j 虽然在数组越界时已出了作用域,但其空间并未收回,因而 i 和 j 就会掩盖越界。而 Release 版由于 i、j 并未其很大作用可能会被优化掉,从而使栈被破坏。

3. _DEBUG 与 NDEBUG :当定义了 _DEBUG 时,assert() 函数会被编译,而 NDEBUG 时不被编译。除此之外,VC++中还有一系列断言宏。这包括:

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 控制。

所有这些断言都只在 Debug版中才被编译,而在 Release 版中被忽略。唯一的例外是 VERIFY() 。事实上,这些宏都是调用了 assert() 函数,只不过附加了一些与库有关的调试代码。如果你在这些宏中加入了任何程序代码,而不只是布尔表达式(例如赋值、能改变变量值的函数调用 等),那么 Release 版都不会执行这些操作,从而造成错误。初学者很容易犯这类错误,查找的方法也很简单,因为这些宏都已在上面列出,只要利用 VC++ 的 Find in Files 功能在工程所有文件中找到用这些宏的地方再一一检查即可。另外,有些高手可能还会加入 #ifdef _DEBUG 之类的条件编译,也要注意一下。
顺便值得一提的是 VERIFY() 宏,这个宏允许你将程序代码放在布尔表达式里。这个宏通常用来检查 Windows API 的返回值。有些人可能为这个原因而滥用 VERIFY() ,事实上这是危险的,因为 VERIFY() 违反了断言的思想,不能使程序代码和调试代码完全分离,最终可能会带来很多麻烦。因此,专家们建议尽量少用这个宏。

4. /GZ 选项:这个选项会做以下这些事

(1) 初始化内存和变量。包括用 0xCC 初始化所有自动变量,0xCD ( Cleared Data ) 初始化堆中分配的内存(即动态分配的内存,例如 new ),0xDD ( Dead Data ) 填充已被释放的堆内存(例如 delete ),0xFD( deFencde Data ) 初始化受保护的内存(debug 版在动态分配内存的前后加入保护内存以防止越界访问),其中括号中的词是微软建议的助记词。这样做的好处是这些值都很大,作为指针是不可能的(而且 32 位系统中指针很少是奇数值,在有些系统中奇数的指针会产生运行时错误),作为数值也很少遇到,而且这些值也很容易辨认,因此这很有利于在 Debug 版中发现 Release 版才会遇到的错误。要特别注意的是,很多人认为编译器会用 0 来初始化变量,这是错误的(而且这样很不利于查找错误)。
(2) 通过函数指针调用函数时,会通过检查栈指针验证函数调用的匹配性。(防止原形不匹配)
(3) 函数返回前检查栈指针,确认未被修改。(防止越界访问和原形不匹配,与第二项合在一起可大致模拟帧指针省略 FPO )

通常 /GZ 选项会造成 Debug 版出错而 Release 版正常的现象,因为 Release 版中未初始化的变量是随机的,这有可能使指针指向一个有效地址而掩盖了非法访问。

除此之外,/Gm /GF 等选项造成错误的情况比较少,而且他们的效果显而易见,比较容易发现。
--------------------------------------------------------------
Release是发行版本,比Debug版本有一些优化,文件比Debug文件小
Debug是调试版本,包括的程序信息更多
Release方法:
build->batch build->build就OK.

-----------------------------------------------------

一、"Debug是调试版本,包括的程序信息更多"

补充:只有DEBUG版的程序才能设置断点、单步执行、使用TRACE/ASSERT等调试输出语句。REALEASE不包含任何调试信息,所以体积小、运行速度快。

二、一般发布release的方法除了hzh_shat(水) 所说的之外,还可以project->Set Active Config,选中release版本。此后,按F5或F7编译所得的结果就是release版本。

转自:http://blog.csdn.net/chenhu_doc/archive/2006/07/17/932305.aspx

分享到:
评论

相关推荐

    CCS中Debug与Release的区别

    除了预设的Debug和Release配置外,CCS还允许用户自定义Build Options集合,以适应特定项目的需求。通过“Project-&gt;Configurations”菜单,用户可以创建新的配置,指定特定的编译参数和优化级别,甚至可以选择是否...

    VC Debug 和 Release的区别

    VC Debug 和 Release 的区别 Debug 和 Release 是 VC 编译选项中的两个重要概念,它们之间的区别主要体现在编译方式、优化选项和 Runtime Library 等方面。理解这两者的区别对 C++ 开发者来说非常重要,因为它们...

    Debug和release的详细区别

    #### 为什么需要区分Debug和Release版本 - **Debug版本**主要用于开发者内部使用,以便于查找和修复错误。它提供了一种易于调试的方式,同时也允许开发者在开发过程中快速迭代和测试新功能。 - **Release版本**则...

    关于Debug_release的区别

    Debug 和 Release 编译方式的区别 Debug 和 Release 编译方式是编程中两种基本的编译方式, Debug 版本是为了调试程序,包含调试信息,不作任何优化;Release 版本是为了发布程序,进行了各种优化,使得程序在代码...

    Debug与Release版本的区别

    Debug 和 Release 版本是两个不同的编译选项,它们的区别在于编译选项的不同。 Debug 版本包括调试信息,因此要比 Release 版本大很多。 Debug 版本用于调试,包含调试信息,不进行优化,而 Release 版本用于发布,...

    delphi debug release区别

    在Delphi编程环境中,"Debug"和"Release"是两种不同的构建配置,它们的主要区别在于编译优化、调试信息和运行效率等方面。了解这两种模式的区别对于开发者来说至关重要,因为它们在开发过程和最终产品发布中起到不同...

    VS2008 Debug与Release的本质区别

    总之,虽然Debug和Release版本之间存在着明显的区别,但这些区别主要是通过不同的编译选项实现的。理解这些选项的作用以及它们如何影响程序的行为对于确保程序的质量至关重要。在实际开发过程中,开发者应充分测试这...

    Debug 和 Release 编译方式的本质区别

    ### Debug 和 Release 编译方式的本质区别 #### 一、Debug与Release编译方式概述 在软件开发领域,为了确保程序质量与效率,通常会采用两种不同的编译配置:Debug模式与Release模式。这两种模式各自拥有不同的编译...

    visual studio不显示Debug,Release的原因及解决办法

    首先,我们需要了解什么是“Debug”和“Release”配置。在Visual Studio中,“Debug”和“Release”是两种主要的构建配置,它们决定了编译器如何处理源代码以创建可执行文件。Debug模式主要用于开发阶段,它包含完整...

    删除debug和release文件夹

    主要用于删除VC编译生成的文件夹debug和release,因为这两个文件夹下的文件太浪费空间了。 利用STL中的queue来存储文件夹名,实现非递归来查找指定的文件夹debug和release。 其实就是找到一个文件夹就加入文件夹队列...

    Visual_Studio中的debug和release版本的区别

    Visual Studio 中的 Debug 和 Release 版本的区别 在 Visual Studio 中,Debug 和 Release 版本是两种不同的编译方式,它们的主要区别在于编译选项的不同。Debug 版本通常称为调试版本,它包含调试信息,并且不作...

    vs开发环境Debug与Release输出路径为同一位置的配置说明

    在Visual Studio (VS)开发环境中,开发者经常需要管理和设置不同的构建配置,如Debug和Release模式。这些配置在编译和调试应用程序时具有不同的优化级别和符号信息,它们的输出路径通常默认不同。然而,有时出于特定...

    stl库在debug-release两种模式下不一致的问题

    然而,在开发过程中,程序员经常遇到一个常见问题:STL库在Debug和Release两种编译模式下的行为不一致。这主要是由于编译器为优化性能和调试便利性而采用的不同策略导致的。 1. **内存分配器的区别** 在Debug模式...

    release模式正常debug模式下报错.docx

    本文将深入探讨Debug和Release模式的区别以及可能导致这种问题的原因。 Debug和Release是Visual Studio(如VS2019)中两种常见的编译配置,它们之间主要的差异在于编译选项和优化程度。Debug模式用于开发和调试,...

    删除Debug和Release文件夹 到回收站

    工作中有时会拷贝VS项目,但是VS项目bin和obj下的Debug、Release文件夹包含很多编译后的文件,这些文件通常没有必要一起拷贝。所以我就写了个小工具给VS项目瘦身。主要功能就是Winform中选择VS项目总目录,删除目录...

    openssl-1.1.1 win32 debug和release库

    "win32-debug" 文件夹则包含调试版本的库文件,这些文件通常有更大的体积,因为它们包含了调试信息,如符号表,这对于调试代码和查找错误非常有用。在开发阶段,应使用调试版本的库来定位和修复问题。 使用这些库...

    判断DLL文件是Debug版或Release版

    在开发过程中,程序员通常会创建两种类型的DLL文件:Debug版和Release版。 Debug版的DLL文件主要用于程序调试。这种版本的DLL包含了额外的调试信息,如源代码行号、变量名以及调试符号等,这些信息可以帮助开发者在...

    为什么debug编译不出错,而release编译会出错

    Debug 和 Release 编译模式之间的差异 Debug 和 Release 编译模式是两种不同的编译模式,分别用于不同的开发阶段。在 Debug 模式下,编译器会插入调试信息,以便于开发者调试程序;而在 Release 模式下,编译器会...

Global site tag (gtag.js) - Google Analytics