Debug&Release
51Testing软件测试网8X7If,@ Py(R_
-dC0i.m?N2N0Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。
&UQ:Y5bS Y7K"Xk0
/^9Q KN.JT4^(|0Debug 和 Release 的真正秘密,在于一组编译选项。下面列出了分别针对二者的选项(当然除此之外还有其他一些,如/Fd /Fo,但区别并不重要,通常他们也不会引起 Release 版错误,在此不讨论)51Testing软件测试网Efk yH!UoAC?R&O
CvK
yl a9g'D0Debug 版本
DR5W SV!Ow;I7ZGA0
r'j!ka)]}0
参数 | 含义 |
/MDd /MLd 或 /MTd | 使用 Debug runtime library (调试版本的运行时刻函数库) |
/Od | 关闭优化开关 |
/D | "_DEBUG" 相当于 #define _DEBUG,打开编译调试代码开关 (主要针对assert函数) |
/ZI | 创建 Edit and continue(编辑继续)数据库,这样在调试过程中如果修改了源代码不需重新编译 |
/GZ | 可以帮助捕获内存错误 |
/Gm | 打开最小化重链接开关, 减少链接时间 |
pd+WFH2V4j'\051Testing软件测试网,}l:gxV8^ C[*f6P
0XO1Ao jn2?lt.U!V0Release 版本
!h
|ar^i*a;wI^a0
"QbB)wxg)Cb051Testing软件测试网]J
{o2v+ygk#Xg/`0N
参数 | 含义 |
/MD /ML 或 /MT | 使用发布版本的运行时刻函数库 |
/O1 或 /O2 | 优化开关,使程序最小或最快 |
/D | "NDEBUG" 关闭条件编译调试代码开关 (即不编译assert函数) |
/GF | 合并重复的字符串, 并将字符串常量放到只读内存, 防止被修改 |
0L,`X
O;L8Vri0
YAZ3KfPV0
-l}GV3?0实际上,Debug 和 Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。
&? KDf])\051Testing软件测试网
\7G*]} rM/L0N!RM
哪些情况下 Release 版会出错51Testing软件测试网&Nub
cX5c7h.Zu
&yq-~'M A{q0有了上面的介绍,我们再来逐个对照这些选项看看 Release 版错误是怎样产生的
u6?Z%V'c7x"_051Testing软件测试网I^1P dh
1、Runtime Library:链接哪种运行时刻函数库通常只对程序的性能产生影响。调试版本的 Runtime Library 包含了调试信息,并采用了一些保护机制以帮助发现错误,因此性能不如发布版本。编译器提供的 Runtime Library 通常很稳定,不会造成 Release 版错误;倒是由于 Debug 的 Runtime Library 加强了对错误的检测,如堆内存分配,有时会出现 Debug 有错但 Release 正常的现象。应当指出的是,如果 Debug 有错,即使 Release 正常,程序肯定是有 Bug 的,只不过可能是 Release 版的某次运行没有表现出来而已。51Testing软件测试网KR9ml g;V-g$o(d.W2cp
SQ]qK1[ MZ8|02、优化:这是造成错误的主要原因,因为关闭优化时源程序基本上是直接翻译的,而打开优化后编译器会作出一系列假设。这类错误主要有以下几种:
/f
eA!K`p
c C051Testing软件测试网:b6Z2A!a+x@:he8y&F
1. 帧指针(Frame Pointer)省略(简称FPO):在函数调用过程中,所有调用信息(返回地址、参数)以及自动变量都是放在栈中的。若函数的声明与实现不同(参数、返回值、调用方式),就会产生错误,但 Debug 方式下,栈的访问通过 EBP 寄存器保存的地址实现,如果没有发生数组越界之类的错误(或是越界“不多”),函数通常能正常执行;Release 方式下,优化会省略 EBP 栈基址指针,这样通过一个全局指针访问栈就会造成返回地址错误是程序崩溃。51Testing软件测试网_4K8S\3y3a
F
51Testing软件测试网cA
i/]7wqDU
C++ 的强类型特性能检查出大多数这样的错误,但如果用了强制类型转换,就不行了。你可以在 Release 版本中强制加入/Oy-编译选项来关掉帧指针省略,以确定是否此类错误。此类错误通常有:MFC 消息响应函数书写错误。正确的应为:51Testing软件测试网"]p/z(s
OL0a){.~
51Testing软件测试网:my
l'f3N9b
|
51Testing软件测试网'w/W(hN{%A }k'w
Bw!}"o%^6ra(c0ON_MESSAGE 宏包含强制类型转换。防止这种错误的方法之一是重定义 ON_MESSAGE 宏,把下列代码加到 stdafx.h 中(在#include "afxwin.h"之后),函数原形错误时编译会报错。51Testing软件测试网/`q8B;oz-x_fe!T
51Testing软件测试网}MLqE#Oq
51Testing软件测试网_*xcs7W1?K*i
|
B%w+Z Gq`051Testing软件测试网-}pC7S3?1{
2. volatile 型变量:volatile 告诉编译器该变量可能被程序之外的未知方式修改(如系统、其他进程和线程)。优化程序为了使程序性能提高,常把一些变量放在寄存器中(类似于 register 关键字),而其他进程只能对该变量所在的内存进行修改,而寄存器中的值没变。
Dy
XfS*H@a0
v-Ao*o-m/o-n0如果你的程序是多线程的,或者你发现某个变量的值与预期的不符而你确信已正确的设置了,则很可能遇到这样的问题。这种错误有时会表现为程序在最快优化出错而最小优化正常。把你认为可疑的变量加上 volatile 试试。51Testing软件测试网]$Y q7s:E5j S?a9[
3. 变量优化:优化程序会根据变量的使用情况优化变量。例如,函数中有一个未被使用的变量,在 Debug 版中它有可能掩盖一个数组越界,而在 Release 版中,这个变量很可能被优化调,此时数组越界会破坏栈中有用的数据。当然,实际的情况会比这复杂得多。与此有关的错误有非法访问,包括数组越界、指针错误等。例如:
V6E7Jd~%S7PQ0
!u1GV$l)F0
|