Debug與Release的區別

VC下Debug和Release區別 程序員

最近寫代碼過程當中,發現 Debug 下運行正常,Release 下就會出現問題,百思不得其解,而Release 下又沒法進行調試,因而只能採用printf方式逐步定位到問題所在處,才發現原來是給定的一個數組未初始化,致使後面處理異常。網上查找了些資料,在這 羅列彙總下,作爲備忘~ 
1、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 並無本質的界限,他們只是一組編譯選項的集合,編譯器只是按照預約的選項行動。 
   

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    it    */   
   found    =    TRUE;   
   break;   
   }    /*    found    it    */   
   }   
   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/     不過要化$的。
相關文章
相關標籤/搜索