VC++中debug跟release編譯模式的區(qū)別總結(jié)
Debug 和 Release 并沒有本質(zhì)的區(qū)別,他們只是VC預(yù)定義提供的兩組編譯選項的集合,編譯器只是按照預(yù)定的選項行動。如果我們愿意,我們完全可以把Debug和Release的行為完全顛倒過來。當(dāng)然也可以提供其他的模式,例如自己定義一組編譯選項,然后命名為MY_ABC等。習(xí)慣上,我們?nèi)匀桓敢馐褂肰C已經(jīng)定義好的名稱。
??? Debug版本包括調(diào)試信息,所以要比Release版本大很多(可能大數(shù)百K至數(shù)M)。至于是否需要DLL支持,主要看你采用的編譯選項。如果是基于 ATL的,則Debug和Release版本對DLL的要求差不多。如果采用的編譯選項為使用MFC動態(tài)庫,則需要MFC42D.DLL等庫支持,而 Release版本需要MFC42.DLL支持。Release不對源代碼進(jìn)行調(diào)試,不考慮MFC的診斷宏,使用的是 MFC? Release庫,編譯時對應(yīng)用程序的速度進(jìn)行優(yōu)化,而Debug則正好相反,它允許對源代碼進(jìn)行調(diào)試,可以定義和使用MFC的
診斷宏,采用MFC? Debug庫,對速度沒有優(yōu)化。???
??? 既然Debug和 Release僅僅是編譯選項的不同,那么為什么要區(qū)分Debug和Release版本呢?
??? Debug和Release,在我看來主要是針對其面 向的目標(biāo)不同的而進(jìn)行區(qū)分的。Debug通常稱為調(diào)試版本,通過一系列編譯選項的配合,編譯的結(jié)果通常包含調(diào)試信息,而且不做任何優(yōu)化,以為開發(fā) 人員提供強大的應(yīng)用程序調(diào)試能力。而Release通常稱為發(fā)布版本,是為用戶使用的,一般客戶不允許在發(fā)布版本上進(jìn)行調(diào)試。所以不保存調(diào)試信 息,同時,它往往進(jìn)行了各種優(yōu)化,以期達(dá)到代碼最小和速度最優(yōu)。為用戶的使用提供便利。
??? 下面僅就默認(rèn)的Debug和Release版本的選項進(jìn)行 比較,詳細(xì)的編譯選項可以看MSDN的說明。
我們將默認(rèn)的Debug和Release的選項設(shè)置進(jìn)行比較,過濾掉相同設(shè)置,主要的不同如下:
編譯選項:/Od /D "_DEBUG" /Gm /RTC1 /MDd /Fo"Debug““" /ZI
鏈接選項:/OUT:"D:“MyProject“l(fā)ogging“Debug“OptionTest.dll" /INCREMENTAL
Release設(shè)置:
編譯選項:/O2 /GL /D "NDEBUG" /FD /MD /Fo"Release““" /Zi
鏈 接選項:/OUT:"D:“MyProject“l(fā)ogging“Release“OptionTest.dll" /INCREMENTAL:NO
Debug? 版本:?
/MDd? /MLd? 或? /MTd? 使用? Debug? runtime? library(調(diào)試版本的運行 時刻函數(shù)庫)?
/Od? 關(guān)閉優(yōu)化開關(guān)?
/D? "_DEBUG"? 相當(dāng)于? #define? _DEBUG,打開編譯調(diào)試代碼 開關(guān)(主要針對assert函數(shù))?
/ZI? 創(chuàng)建? Edit? and? continue數(shù)據(jù)庫,在調(diào)試 過程中如果修改了源代碼不需重新編譯?
/GZ? 可以幫助捕獲內(nèi)存錯誤?
/Gm? 打開最小化重鏈接開關(guān),減少鏈接時 間?
Release? 版本:???
/MD? /ML? 或? /MT? 使用發(fā)布版本的運行時刻函數(shù)庫?
/O1? 或? /O2? 優(yōu) 化開關(guān),使程序最小或最快?
/D? "NDEBUG"? 關(guān)閉條件編譯調(diào)試代碼開關(guān)(即不編譯assert函數(shù))?
/GF? 合并重 復(fù)的字符串,并將字符串常量放到只讀內(nèi)存,防止被修改?
MDd與MD
??? 首 先,Debug版本使用調(diào)試版本的運行時庫(/MDd選項),Relase版本則使用的是發(fā)布版本的運行時庫(vcrt.dll)。其區(qū)別主要在于運行時 的性能影響。調(diào)試版本的運行時庫包含了調(diào)試信息,并采用了一些保護(hù)機(jī)制以幫助發(fā)現(xiàn)錯誤,也因此,其性能不如發(fā)布版本。編譯器提供的Runtime Library很穩(wěn)定,不會造成Release版本錯誤,倒是由于Debug版本的Runtime Library加強了對錯誤的檢測,如堆內(nèi)存分配檢查等,反而會報告錯誤,應(yīng)當(dāng)指出,如果Debug有錯誤,而Release版本正常,程序肯定是有
Bug的,只是我們還沒有發(fā)現(xiàn)。
ZI與Zi
??? 其次,/ZI選項與/Zi選項。通過使用/ZI選項,可以在調(diào)試過程修改代碼 而不需要重新編譯。這是個調(diào)試的好幫手,可如果我們使用Release版本,這將變得不可行。
Od與O2
/O2與/Od 選項:Od是關(guān)閉編譯器優(yōu)化,普遍用于Debug版本。而O2選項是創(chuàng)建最快速代碼,這當(dāng)然是Release版本的不二選擇。
RTCx選 項
/RTCx選項讓編譯器插入動態(tài)檢測代碼以幫助你檢測程序中的錯誤。比如,它會將局部變量初始化為非零值。包括用 0xCC初始化所有自動變量,0xCD初始化堆中分配的內(nèi)存(即new的內(nèi)存),使用0xDD填充被釋放的內(nèi)存(即delete的內(nèi)存),0xFD初始化 受保護(hù)的內(nèi)存(debug版在動態(tài)分配內(nèi)存的前后加入保護(hù)內(nèi)存以防止越界訪問)。這樣做的好處是這些值都很大,一般不可能作為指針,考試,大提示作為數(shù)值 也很少用到,而且這些值很容易辯認(rèn),因此有利于在Debug版本中發(fā)現(xiàn)Release版才會遇到的錯誤。另外,通過函數(shù)指針調(diào)用函數(shù)時,會通過檢
查棧指針驗證函數(shù)調(diào)用的匹配性(防止原型不匹配)。使用/RTCx選項會造成Debug版本出錯,而Release版本正常的現(xiàn)象,因為 Release版中未初始化的變量是隨機(jī)的,很可能使指針指向了有效但是錯誤的地址,從而掩蓋了錯誤。這個編譯選項只能在/Od選項下使用。
Gm,INCREMENTAL or NO
編譯選項中的Gm和鏈接選項中的 INCREMENTAL都只為一個目的,加快編譯速度。我們經(jīng)常遇上這樣的問題,只修改了一個頭文件,結(jié)果卻造成所有動態(tài)庫的重新編譯。而這兩個選項就是 為了解決這樣的問題。如果啟用了/Gm開關(guān),編譯器在項目中的.idb文件中存儲了源文件和類定義之間的依賴關(guān)系。之后的編譯過程中使用.idb 文件中的信息確定是否需要編譯某個源文件,哪怕是此源文件已經(jīng)包含了已修改的.h文件。
INCREMENTAL開關(guān)默認(rèn)是開啟的。使用增量鏈接生 成的可執(zhí)行文件或者動態(tài)鏈接庫會大于非增量鏈接的程序,因為有代碼和數(shù)據(jù)的填充。另外,增量鏈接的文件還包含跳轉(zhuǎn)trunk以處理函數(shù)重定位到新地址。
MSDN 上明確指出:為確保最終發(fā)布版本不包含填充或者trunk,請非增量鏈接程序。
/GZ? 選項:做以下這些事?
1.初 始化內(nèi)存和變量。包括用? 0xCC? 初始化所有自動變量,0xCD? (? Cleared? Data? )? 初始化堆中分配的內(nèi)存(即動態(tài)分配 的內(nèi)存,例如? new? ),0xDD? (? Dead? Data? )? 填充已被釋放的堆內(nèi)存(例 如? delete? ),0xFD(? deFencde? Data? )? 初始化受保護(hù)的內(nèi)存(debug? 版在動態(tài)分配內(nèi)存的前后加入保護(hù)內(nèi) 存以防止越界訪問),其中括號中的詞是微軟建議的助記詞。這樣做的好處是這些值都很大,作為指針是不可能的(而且?
32? 位系統(tǒng)中指針很少是奇數(shù)值, 在有些系統(tǒng)中奇數(shù)的指針會產(chǎn)生運行時錯誤),作為數(shù)值也很少遇到,而且這些值也很容易辨認(rèn),因此這很有利于在? Debug? 版中發(fā) 現(xiàn)? Release? 版才會遇到的錯誤。要特別注意的是,很多人認(rèn)為編譯器會用? 0? 來初始化變量,這是錯誤的(而且這樣很不利于查找錯 誤)。?
2.?? 通過函數(shù)指針調(diào)用函數(shù)時,會通過檢查棧指針驗證函數(shù)調(diào)用的匹配性。(防止原形不匹配)?
3.?? 函數(shù)返回前檢查 棧指針,確認(rèn)未被修改。(防止越界訪問和原形不匹配,與第二項合在一起可大致模擬幀指針省略? FPO? )?
??? 通常? /GZ? 選 項會造成? Debug? 版出錯而? Release? 版正常的現(xiàn)象,因為? Release? 版中未初始化的變量是隨機(jī)的,這有可能使指針指向一 個有效地址而掩蓋了非法訪問。?
_DEBUG與NDEBUG
這是最重要的一個選項。這兩個是編譯器的預(yù)處理器定義,默認(rèn)情況下_DEBUG用于Debug版本,而NDEBUG用于Release版本。 它們可以說是重要的無以復(fù)加。因為,assert系列的斷言僅僅在_DEBUG下生效!
下面是assert.h文件中摘出來的:
C++代碼 ?#ifdef?NDEBUG??#define?assert(_Expression)?????((void)0)??#else??/*?NDEBUG?*/??#ifdef?__cplusplus??extern?"C"?{??#endif??/*?__cplusplus?*/??_CRTIMP?void?__cdecl?_wassert(__in_z?const?wchar_t?*?_Message,?__in_z?const?wchar_t?*_File,?__in?unsigned?_Line);??#ifdef?__cplusplus??}??#endif??/*?__cplusplus?*/??#define?assert(_Expression)?(void)(?(!!(_Expression))?||?(_wassert(_CRT_WIDE(#_Expression),?_CRT_WIDE(__FILE__),?__LINE__),?0)?)??#endif??/*?NDEBUG?*/??
可以看出在未定義_DEBUG時,assert變成一條空語句不被執(zhí)行。
也就是說,我們現(xiàn)在所有發(fā)布的版本無法使 用斷言機(jī)制進(jìn)行程序調(diào)試。
相關(guān)經(jīng)驗:
1. 變量。
??? 大家都知道,debug跟release在初始化變量時所做的操作是不同的,debug是將每個字節(jié)位都賦成0xcc, 而release的賦值近似于隨機(jī)。如果你的程序中的某個變量沒被初始化就被引用,就很有可能出現(xiàn)異常:用作控制變量將導(dǎo)致流程導(dǎo)向不一致;用作數(shù)組下標(biāo)將會使程序崩潰;更加可能是造成其他變量的不準(zhǔn)確而引起其他的錯誤。所以在聲明變量后馬上對其 初始化一個默認(rèn)的值是最簡單有效的辦法,否則項目大了你找都沒地方找。代碼存在錯誤在debug方式下可能會忽略而不被察覺到。debug方式下數(shù)組越界也大多不會出錯,在release中就暴露出來了,這個找起來就比較難了。
2. 自定義消息的消息參數(shù)。
?? MFC為我們提供了很好的消息機(jī)制,更增加了自定義消息,好處我就不用多說了。這也存在debug跟release的問 題嗎?答案是肯定的。在自定義消息的函數(shù)體聲明時,時常會看到這樣的寫法:afx_msg LRESULT OnMessageOwn(); Debug 情況下一般不會有任何問題,而當(dāng)你在Release下且多線程或進(jìn)程間使用了消息傳遞時就會導(dǎo)致無效句柄之類的錯誤。導(dǎo)致這個錯誤直接原因是消息體的參數(shù) 沒有添加,即應(yīng)該寫 成:afx_msg LRESULT OnMessageOwn(WPARAM wparam,
LPARAM lparam); 3. release模式下不出錯,但debug模式下報錯。
??? 這種情況下大多也是因為代碼書寫不正確引起的,查看MFC 的源碼,可以發(fā)現(xiàn)好多ASSERT的語句(斷言),這個宏只是在debug模式下才有效,那么就清楚了,release版不報錯是忽略了錯誤而不是沒有錯誤,這可能存在很大的隱患,因為是Debug模式下,比較方便調(diào)試,好好的檢查自己的代碼,再此就不多說了。
3. ASSERT, VERIFY, TRACE.......... 調(diào)試宏
??? 這種情況很容易解釋。舉個例子:請在VC下輸入ASSERT然后選中按F12跳到宏定義的地方,這里你就能夠發(fā)現(xiàn)Debug中 ASSERT要執(zhí)行AfxAssertFailedLine,而Release下的宏定義卻為"#define ASSERT(f) ((void)0)"。所以注意在這些調(diào)試宏的語句不要用程序相關(guān)變量如i++寫操作的語句。
VERIFY 是個例外,"#define VERIFY(f) ((void)(f))",即執(zhí)行。
哪些情況下Release版會出錯??
1.? Runtime? Library:鏈接哪種運行時刻函數(shù)庫通常只對程序的性能產(chǎn)生影響。調(diào)試版本 的? Runtime? Library? 包含了調(diào)試信息,并采用了一些保護(hù)機(jī)制以幫助發(fā)現(xiàn)錯誤,因此性能不如發(fā)布版本。編譯器提供 的? Runtime? Library? 通常很穩(wěn)定,不會造成? Release? 版錯誤;倒是由 于? Debug? 的? Runtime? Library? 加強了對錯誤的檢測,如堆內(nèi)存分配,有時會出現(xiàn)? Debug? 有錯 但? Release? 正常的現(xiàn)象。應(yīng)當(dāng)指出的是,如果?
Debug? 有錯,即使? Release? 正常,程序肯定是有? Bug? 的,只不 過可能是? Release? 版的某次運行沒有表現(xiàn)出來而已。
?
2.? 優(yōu)化:這是造成錯誤的主要原因,因為關(guān)閉優(yōu)化時源程序基本上是直接翻譯的,而打開優(yōu)化后編譯器會作出一系列假設(shè)。這類錯誤主要有以下幾種:?
(1)? 幀指針 (Frame? Pointer)省略(簡稱? FPO? ):在函數(shù)調(diào)用過程中,所有調(diào)用信息(返回地址、參數(shù))以及自動變量都是放在棧中的。若函數(shù)的聲明與實現(xiàn)不同(參數(shù)、返回值、調(diào)用方式),就會產(chǎn)生錯誤,但? Debug? 方式下,棧的訪問通過? EBP? 寄存器保存的地址實現(xiàn),如果沒 有發(fā)生數(shù)組越界之類的錯誤(或是越界“不多”),函數(shù)通常能正常執(zhí)行;Release? 方式下,優(yōu)化會省略? EBP? ?;分羔槪@樣通過一個全局 指針訪問棧就會造成返回地址錯誤是程序崩潰。C++? 的強類型特性能檢查出大多數(shù)這樣的錯誤,但如果用了強制類型轉(zhuǎn)換,就不行了。你可以
在? Release? 版本中強制加入? /Oy-? 編譯選項來關(guān)掉幀指針省略,以確定是否此類錯誤。此類錯誤通常有:?
MFC消息響應(yīng)函數(shù)書寫錯誤。正確的應(yīng)為?
afx_msg? LRESULT? OnMessageOwn(WPARAM? wparam,? LPARAM? lparam);?
ON_MESSAGE? 宏 包含強制類型轉(zhuǎn)換。防止這種錯誤的方法之一是重定義? ON_MESSAGE? 宏,把下列代碼加到? stdafx.h? 中 (在#include? "afxwin.h"之后),函數(shù)原形錯誤時編譯會報錯?
C++代碼 ?#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? 告訴編譯器該變量可能被程序之外的未知方式修改(如系統(tǒng)、其他進(jìn)程和線程)。優(yōu)化程序為了使程序性能提高,常把一些變量放在寄存器中(類似于? register? 關(guān)鍵字),而其他進(jìn)程只能對該變量所在的內(nèi)存進(jìn)行修改,而寄存器中的 值沒變。如果你的程序是多線程的,或者你發(fā)現(xiàn)某個變量的值與預(yù)期的不符而你確信已正確的設(shè)置了,則很可能遇到這樣的問題。這種錯誤有時會表現(xiàn)為程序在最快 優(yōu)化出錯而最小優(yōu)化正常。把你認(rèn)為可疑的變量加上? volatile? 試試。?
(3)? 變量優(yōu)化:優(yōu)化程序會根據(jù)變量的使用情況優(yōu)化變量。例如,函數(shù)中有一個未被使用的變量,在? Debug? 版中它有可能掩蓋一個數(shù)組越界,而在? Release? 版中,這個變量很可能被 優(yōu)化調(diào),此時數(shù)組越界會破壞棧中有用的數(shù)據(jù)。當(dāng)然,實際的情況會比這復(fù)雜得多。與此有關(guān)的錯誤有:?
??? 非法訪問,包括數(shù)組越界、指針錯誤 等。例如?
C++代碼 ?void??fn(void)????{????????int??i;????????i??=??1;???????int??a[4];???????{??????????int??j;??????????j??=??1;???????}???????a[-1]??=??1;?//當(dāng)然錯誤不會這么明顯,例如下標(biāo)是變量???????a[4]??=??1;????}????
j? 雖然在數(shù)組越界時已出了作用域,但其空間并未收回,因而? i? 和? j? 就會掩蓋越界。而? Release? 版由于? i、j? 并未其很大作用可能會被優(yōu)化掉,從而使棧被破壞。?
3.? _DEBUG? 與? NDEBUG? :當(dāng)定義了? _DEBUG? 時,assert()? 函數(shù)會被編譯, 而? 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()? 。事實上,這些宏都是調(diào)用了? assert()? 函數(shù),只不過附加了一些與庫有關(guān)的調(diào)試代碼。如果你在這些宏中加入了任何 程序代碼,而不只是布爾表達(dá)式(例如賦值、能改變變量值的函數(shù)調(diào)用? 等),那么? Release? 版都不會執(zhí)行這些操作,從而造成錯誤。初學(xué)者很容 易犯這類錯誤,查找的方法也很簡單,因為這些宏都已在上面列出,只要利用? VC++? 的? Find? in? Files? 功能在工程所有文件中
找到用這些宏的地方再一一檢查即可。另外,有些高手可能還會加入? #ifdef? _DEBUG? 之類的條件編譯,也要注意一下。?
順便值 得一提的是? VERIFY()? 宏,這個宏允許你將程序代碼放在布爾表達(dá)式里。這個宏通常用來檢查? Windows? API? 的返回值。有些人 可能為這個原因而濫用? VERIFY()? ,事實上這是危險的,因為? VERIFY()? 違反了斷言的思想,不能使程序代碼和調(diào)試代碼完全分離, 最終可能會帶來很多麻煩。因此,專家們建議盡量少用這個宏。?
一、"Debug是調(diào)試版本,包括的程序信息更多"?
補充:只有DEBUG版的程序才能設(shè)置斷點、單步執(zhí)行、使用 TRACE/ASSERT等調(diào)試輸出語句。REALEASE不包含任何調(diào)試信息,所以體積小、運行速度快。
I.??? 內(nèi)存分配問題??
?? 1.??? 變量未初始化。下面的程序在debug中運行的很好。??
C++代碼 ?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版中則不會。所以盡可能的給變量、類或結(jié)構(gòu) 初始化。??
???
?? 2.??? 數(shù)據(jù)溢出的問題??
?? 如:
C++代碼 ?char????buffer[10];?????int????counter;?????lstrcpy(buffer,????"abcdefghik");?????
?? 在debug版中buffer的NULL覆蓋了counter的高位,但是除非counter>16M,什么問題也 沒有。但是在release版 中,counter可能被放在寄存器中,這樣NULL就覆蓋了buffer下面的空間,可能就是函數(shù)的返回地址,這將導(dǎo)致 ACCESS??? ERROR。??
???
?? 3.??? DEBUG版和RELEASE版的內(nèi)存分配方式是不同的??? 。如果你在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宏是這樣定義的??
C++代碼 ????#ifdef????_DEBUG?????#define????ASSERT(x)????if(????(x)????==????0)????report_assert_failure()?????#else?????#define????ASSERT(x)?????#endif?????
?? 實際上復(fù)雜一些,但無關(guān)緊要。假如你在這些語句中加了程序中必須要有的代碼??
?? 比如??
C++代碼 ????ASSERT(pNewObj????=????new????CMyClass);????????pNewObj->MyFunction();?????
??
?? 這種時候Release版本中的pNewObj不會分配到空間??
???
?? 所以執(zhí)行到下一個語句的時候程序會報該程序執(zhí)行了非法操作的錯誤。這時可以用VERIFY??? :??
C++代碼 ????#ifdef????_DEBUG?????#define????VERIFY(x)????if(????(x)????==????0)????report_assert_failure()?????#else?????#define????VERIFY(x)????(x)?????#endif???
?
?? 這樣的話,代碼在release版中就可以執(zhí)行了。??
???
?? III.??? 參數(shù)問題:??
???
?? 自定義消息的處理函數(shù),必須定義如下:??
?? afx_msg??? LRESULT??? OnMyMessage(WPARAM,??? LPARAM);??
?? 返回值必須是HRESULT型,否則Debug會過,而Release出錯??
???
?? IV.??? 內(nèi)存分配??
?? 保證數(shù)據(jù)創(chuàng)建和清除的統(tǒng)一性:如果一個DLL提供一個能夠創(chuàng)建數(shù)據(jù)的函數(shù),那么這個DLL同時應(yīng)該提供一個函數(shù)銷毀這些數(shù)據(jù)。數(shù)據(jù)的創(chuàng)建和清除應(yīng)該在同一 個層次上。??
???
?? V.??? DLL的災(zāi)難??
?? 人們將不同版本DLL混合造成的不一致性形象的稱為??? “動態(tài)連接庫的地獄“(DLL??? Hell)??? ,甚至微軟自己也這么說 。??
???
?? 如果你的程序使用你自己的DLL時請注意:??
???
?? 1.??? 不能將debug和release版的DLL混合在一起使用。debug都是debug版,release版都是release版。??
?? 解決辦法是將debug和release的程序分別放在主程序的debug和release目錄下??
???
?? 2.??? 千萬不要以為靜態(tài)連接庫會解決問題,那只會使情況更糟糕。??
???
?? VI.??? RELEASE版中的調(diào)試??? :??
?? 1.??? 將ASSERT()??? 改為??? VERIFY()??? 。找出定義在"#ifdef??? _DEBUG"中的代碼,如果在RELEASE版本中需要這些代碼請將他們移到定義外。查找TRACE(...)中代碼,因為這些代碼在RELEASE中 也不被編譯。??? 請認(rèn)真檢查那些在RELEASE中需要的代碼是否并沒有被便宜。??
?? 2.??? 變量的初始化所帶來的不同,在不同的系統(tǒng),或是在DEBUG/RELEASE版本間都存在這樣的差異,所以請對變量進(jìn)行初始化。??
?? 3.??? 是否在編譯時已經(jīng)有了警告?請將警告級別設(shè)置為3或4,然后保證在編譯時沒有警告出現(xiàn).??
?? VII.??? 將Project??? Settings"??? 中??? "C++/C??? "??? 項目下優(yōu)化選項改為Disbale(Debug)。編譯器的優(yōu)化可能導(dǎo)致許多意想不到的錯誤,
???
?? 1.??? 此外對RELEASE版本的軟件也可以進(jìn)行調(diào)試,請做如下改動:??
???
?? 在"Project Settings"中"C++/C"項目下設(shè)置"category"為"General"并且將"Debug??? Info"設(shè)置為"Program Database"。??
???
?? 在"Link"項目下選中"Generate Debug Info"檢查框。??
???
?? "Rebuild All"??
???
?? 如此做法會產(chǎn)生的一些限制:??
???
?? 無法獲得在MFC DLL中的變量的值。??
???
?? 必須對該軟件所使用的所有DLL工程都進(jìn)行改動。??
???
?? 另:??
???
?? 1. MS BUG:MS的一份技術(shù)文檔中表明,在VC5中對于DLL的"Maximize??? Speed"優(yōu)化選項 并未被完全支持,因此這將會引起內(nèi)存錯誤并導(dǎo)致程序崩潰。??
???
?? 2. 有 一個程序DebugView,用來捕捉OutputDebugString的輸出,運行起來后(估計是自設(shè)為system debugger)就可以觀看所有程序的OutputDebugString的輸出。此后,你可以脫離VC來運行你的程序并觀看調(diào)試信息。??
???
?? 3.??? 有一個叫Gimpel??? Lint的靜態(tài)代碼檢查工具,據(jù)說比較好用? ?不過要化$的。
Debug與Release不同的問題在剛開始編寫代碼時會經(jīng)常發(fā)生,99%是因為你的代碼書寫錯誤而導(dǎo)致的,所以不要動不動就說系統(tǒng)問 題或編譯器問題,努力找找自己的原因才是根本。我從前就常常遇到這情況,經(jīng)歷過一次次的教訓(xùn)后我就開始注意了,現(xiàn)在我所寫過的代碼我已經(jīng)好久沒遇到這種問 題了。下面是幾個避免的方面,即使沒有這種問題也應(yīng)注意一下:
1. 注意變量的初始化,尤其是指針變量,數(shù)組變量的初始化(很大的情況下另作考 慮了)。
2. 自定義消息及其他聲明的標(biāo)準(zhǔn)寫法
3. 使用調(diào)試宏時使用后最好注釋掉
4. 盡量使用 try - catch(...)
5. 盡量使用模塊,不但表達(dá)清楚而且方便調(diào)試。