Debug與Release版本區別

來源:互聯網
上載者:User

標籤:style   blog   io   ar   使用   sp   strong   檔案   資料   


Debug與Release版本區別  


Debug版本就是調試版本,Visual C++ 6.0預設的就是Debug版本。在Debug版本中,可以使用逐步執行、跟蹤等功能,但其產生的可執行檔比較大,代碼運行比較慢。Release版本就是發行版本,其運行速度較快,可執行檔較小,但在其編譯條件下無法執行調試功能。  

    還有一點,Release版本的exe檔案連結的目標是標準的MFC DLL(Use MFC in a shared or static dll)。比如MFC42.DLL。這些DLL在安裝windows的時候,就會裝到系統中。因此,這樣的exe在沒有安裝Visual C++ 6.0的機器上也能運行。而Debug版本的exe連結了調試版本的MFC DLL檔案,比如MFC42.DLL。在沒有安裝Visual C++ 6.0的機器上不能運行,因為缺少MFC42D.DLL等,除非選擇use static dll when link。   

    Debug版本中包含大量的調試資訊,所以我們能夠逐步執行、Watch運算式等等,而release版本僅包含我們的代碼。由於要利於程式的測試,Debug版本的程式附帶很多測試資訊和測試程式時才需要的代碼,所以Debug版本的程式需要VC的Debug(注意這裡不是指程式的Debug,而是指VC的調試器)才能運行。而Release版本就不具有這些特性,所以在Release版本的程式上不能做調試!打包就相當於將你製作的東西發布出去,應該是最佳化過的代碼,當然要用發布版本,即Release版本。   

    兩者所用的動態串連庫是不一樣的,Release版本所需要的dll和lib已經包含在Windows的system(或者system32)下,所以只需要拷貝就可以運行了,但是Debug版本需要的dll和lib是在安裝vc時裝上去的,如果你想直接將debug版本給使用者,需要拷貝幾個檔案,但這樣顯得很臃腫,一般來說不可取。


    兩個問題的解答:

問:

1、我是否只要在“Set Active Configuration”裡設定為“Win32 Release”就可以得到Release版本?

2、我編的一個程式在Release下編譯不成功,在Debug下編譯成功。那麼,如果我把Debug版程式給別人使用,會有問題嗎?

答:

1.基本是這樣。前提是你沒有加入用於debug的先行編譯命令。  這樣可以,然後編譯運行,這時,在你的工程目錄下會產生一個叫release的目  錄,裡面有你的release程式。

2.不行啊,Debug版是包含debug資訊的。  Release版不要系統的某些動態串連庫的支援,軟體的發布一般用release版  Debug要好幾個動態串連庫的支援,又好幾兆。  另外,你的Release下編譯不成功應該和你的環境配置有關,可以看看project->  setting,在debug和Release兩種方式有什麼不同。

一、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     等選項造成錯誤的情況比較少,而且他們的效果顯而易見,比較容易發現。

Debug與Release版本區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.