Debug和Release差別
VC下Debug和Release差別
最近寫代碼過程中,發現 Debug 下運作正常,Release 下就會出現問題,百思不得其解,而Release 下又無法進行調試,于是隻能采用printf方式逐漸定位到問題所在處,才發現原來是給定的一個數組未初始化,導緻後面處理異常。網上查找了些資料,在這 羅列彙總下,做為備忘~
一、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 并沒有本質的界限,他們隻是一組編譯選項的集合,編譯器隻是按照預定的選項行動。
相關經驗: 轉自http://dev.csdn.net/article/17/17068.shtm
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 = TRUE;
break;
}
}
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/ 不過要化$的。
轉載自: http://www.cnblogs.com/JemBai/archive/2009/01/13/1374805.html 部落格園: 草原和大樹