知识大全 关于Debug和Release之本质区别的讨论

Posted 变量

篇首语:历览千载书,时时见遗烈。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 关于Debug和Release之本质区别的讨论相关的知识,希望对你有一定的参考价值。

关于Debug和Release之本质区别的讨论  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  一 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 使用发布版本的运行时刻函数库

  /O 或 /O 优化开关 使程序最小或最快

  /D NDEBUG 关闭条件编译调试代码开关(即不编译assert函数)

  /GF 合并重复的字符串 并将字符串常量放到只读内存 防止

  被修改

  实际上 Debug 和 Release 并没有本质的界限 他们只是一组编译选项的集合 编译器只是按照预定的选项行动 事实上 我们甚至可以修改这些选项 从而得到优化过的调试版本或是带跟踪语句的发布版本

  二 哪些情况下 Release 版会出错

  有了上面的介绍 我们再来逐个对照这些选项看看 Release 版错误是怎样产生的

   Runtime Library 链接哪种运行时刻函数库通常只对程序的性能产生影响 调试版本的 Runtime Library 包含了调试信息 并采用了一些保护机制以帮助发现错误 因此性能不如发布版本 编译器提供的 Runtime Library 通常很稳定 不会造成 Release 版错误 倒是由于 Debug 的 Runtime Library 加强了对错误的检测 如堆内存分配 有时会出现 Debug 有错但 Release 正常的现象 应当指出的是 如果 Debug 有错 即使 Release 正常 程序肯定是有 Bug 的 只不过可能是 Release 版的某次运行没有表现出来而已

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

  ( ) 帧指针(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 AfxSig_lwl (AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL CWnd *)(WPARAM LPARAM) > (&memberFxn)

  ( ) volatile 型变量 volatile 告诉编译器该变量可能被程序之外的未知方式修改(如系统 其他进程和线程) 优化程序为了使程序性能提高 常把一些变量放在寄存器中(类似于 register 关键字) 而其他进程只能对该变量所在的内存进行修改 而寄存器中的值没变 如果你的程序是多线程的 或者你发现某个变量的值与预期的不符而你确信已正确的设置了 则很可能遇到这样的问题 这种错误有时会表现为程序在最快优化出错而最小优化正常 把你认为可疑的变量加上 volatile 试试

  ( ) 变量优化 优化程序会根据变量的使用情况优化变量 例如 函数中有一个未被使用的变量 在 Debug 版中它有可能掩盖一个数组越界 而在 Release 版中 这个变量很可能被优化调 此时数组越界会破坏栈中有用的数据 当然 实际的情况会比这复杂得多 与此有关的错误有

  ● 非法访问 包括数组越界 指针错误等 例如

  

  void fn(void) int i; i = ; int a[ ]; int j; j = ; a[ ] = ;//当然错误不会这么明显 例如下标是变量 a[ ] = ;

  j 虽然在数组越界时已出了作用域 但其空间并未收回 因而 i 和 j 就会掩盖越界 而 Release 版由于 i j 并未其很大作用可能会被优化掉 从而使栈被破坏

   _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() 违反了断言的思想 不能使程序代码和调试代码完全分离 最终可能会带来很多麻烦 因此 专家们建议尽量少用这个宏

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

  ( ) 初始化内存和变量 包括用 xCC 初始化所有自动变量 xCD ( Cleared Data ) 初始化堆中分配的内存(即动态分配的内存 例如 new ) xDD ( Dead Data ) 填充已被释放的堆内存(例如 delete ) xFD( deFencde Data ) 初始化受保护的内存(debug 版在动态分配内存的前后加入保护内存以防止越界访问) 其中括号中的词是微软建议的助记词 这样做的好处是这些值都很大 作为指针是不可能的(而且 位系统中指针很少是奇数值 在有些系统中奇数的指针会产生运行时错误) 作为数值也很少遇到 而且这些值也很容易辨认 因此这很有利于在 Debug 版中发现 Release 版才会遇到的错误 要特别注意的是 很多人认为编译器会用 来初始化变量 这是错误的(而且这样很不利于查找错误)

  ( ) 通过函数指针调用函数时 会通过检查栈指针验证函数调用的匹配性 (防止原形不匹配)

  ( ) 函数返回前检查栈指针 确认未被修改 (防止越界访问和原形不匹配 与第二项合在一起可大致模拟帧指针省略 FPO )

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

cha138/Article/program/net/201311/11874

相关参考

社会主义和资本主义的本质区别是

社会主义和资本主义的本质区别是_____。A、生产力的性质和发展水平不同B、社会基本矛盾不同C、生产关系和上层建筑的不同D、意识形态的不同答案:C解析:社会形态划分的标准是生产关系。故本题答案选C。

知识大全 Oracle的函数vsize和length的区别讨论

Oracle的函数vsize和length的区别讨论  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

真相和假象的区别在于真相是表现本质的,假象是不表现本质的

真相和假象的区别在于真相是表现本质的,假象是不表现本质的。_____答案:错误解析:现象是事物的外部联系和表面特征,是事物的外在表现。现象可以分为真相和假象。真相是从正面直接表现本质的现象,假象是从反

知识大全 喜欢和爱的真正含义是什么,本质上有什么区别

喜欢和爱的真正含义是什么,本质上有什么区别?喜欢」与「爱」是同一回事吗?喜欢和爱有什么区别?究竟是喜欢还是爱,你该如何判断?正常男女交往模式大约是:相识→较密切的交往→作决定以固定两人之间的爱情关系→

农业区别于其他产业的本质特征是

农业区别于其他产业的本质特征是_____。A、农业生产过程是生物依靠自然环境和自身生理机能而进行的自然生长发育的过程B、农业生产过程是在一定的生产方式中,人们通过有目的的活动,利用动植物的生理机能和改

知识大全 燃油附加税和燃油附加费之间有什么本质的区别

燃油附加税和燃油附加费之间有什么本质的区别?别回答说"税和费"的区别!  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶

马克思主义认为,人与动物的本质区别在于__

马克思主义认为,人与动物的本质区别在于_____。A、人能制造和使用生产工具从事生产劳动B、人是自然属性和社会属性的统一C、人有语言文字和宗教信仰D、人有意识和抽象思维能力答案:A解析:马克思主义认为

知识大全 社会主义的根本任务、根本目标、本质有什么区别

社会主义的根本任务、根本目标、本质有什么区别社会主义的根本任务是发展生产力目标是发展生产力和实现共同富裕社会主义的本质,是解放生产力,发展生产力,消灭剥削,消除两极分化,最终达到共同富裕社会主义的根本

知识大全 在Oracle10g Release 2中的Autotrace

在Oracle10gRelease2中的Autotrace  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一

法律议案是法律制定机关开会时,提请该机关列入日程讨论的关于法律制定、修改和废除的提案或建议

法律议案是法律制定机关开会时,提请该机关列入日程讨论的关于法律制定、修改和废除的提案或建议。_____答案:正确解析:法律议案的提出:法律议案是法律制定机关开会时,提请该机关列入日程讨论的关于法律制定