VC下Debug和Release區(qū)別

字號(hào):

最近寫代碼過(guò)程中,發(fā)現(xiàn) Debug 下運(yùn)行正常,Release 下就會(huì)出現(xiàn)問(wèn)題,百思不得其解,而Release 下又無(wú)法進(jìn)行調(diào)試,于是只能采用printf方式逐步定位到問(wèn)題所在處,才發(fā)現(xiàn)原來(lái)是給定的一個(gè)數(shù)組未初始化,導(dǎo)致后面處理異常。網(wǎng)上查找了些資料,在這羅列匯總下,做為備忘~
    一、Debug 和 Release 的區(qū)別
     Debug 通常稱為調(diào)試版本,它包含調(diào)試信息,并且不作任何優(yōu)化,便于程序員調(diào)試程序。Release 稱為發(fā)布版本,它往往是進(jìn)行了各種優(yōu)化,使得程序在代碼大小和運(yùn)行速度上都是的,以便用戶很好地使用。
     Debug 和 Release 的真正區(qū)別,在于一組編譯選項(xiàng)。
    Debug 版本
     參數(shù) 含義
    /MDd /MLd 或 /MTd 使用 Debug runtime library(調(diào)試版本的運(yùn)行時(shí)刻函數(shù)庫(kù))
    /Od 關(guān)閉優(yōu)化開(kāi)關(guān)
    /D "_DEBUG" 相當(dāng)于 #define _DEBUG,打開(kāi)編譯調(diào)試代碼開(kāi)關(guān)(主要針對(duì)assert函數(shù))
    /ZI
    創(chuàng)建 Edit and continue(編輯繼續(xù))數(shù)據(jù)庫(kù),這樣在調(diào)試過(guò)程中如果修改了源代碼不需重新編譯
    GZ 可以幫助捕獲內(nèi)存錯(cuò)誤
    Release 版本 參數(shù)含義
     /MD /ML 或 /MT 使用發(fā)布版本的運(yùn)行時(shí)刻函數(shù)庫(kù)
    /O1 或 /O2 優(yōu)化開(kāi)關(guān),使程序最小或最快
    /D "NDEBUG" 關(guān)閉條件編譯調(diào)試代碼開(kāi)關(guān)(即不編譯assert函數(shù))
    /GF 合并重復(fù)的字符串,并將字符串常量放到只讀內(nèi)存,防止被修改
    Debug 和 Release 并沒(méi)有本質(zhì)的界限,他們只是一組編譯選項(xiàng)的集合,編譯器只是按照預(yù)定的選項(xiàng)行動(dòng)。
    相關(guān)經(jīng)驗(yàn): 轉(zhuǎn)自http://dev.csdn.net/article/17/17068.shtm
    1. 變量。
     大家都知道,debug跟release在初始化變量時(shí)所做的操作是不同的,debug是將每個(gè)字節(jié)位都賦成0xcc(注1),而release的賦值近似于隨機(jī)(我想是直接從內(nèi)存中分配的,沒(méi)有初始化過(guò))。這樣就明確了,如果你的程序中的某個(gè)變量沒(méi)被初始化就被引用,就很有可能出現(xiàn)異常:用作控制變量將導(dǎo)致流程導(dǎo)向不一致;用作數(shù)組下標(biāo)將會(huì)使程序崩潰;更加可能是造成其他變量的不準(zhǔn)確而引起其他的錯(cuò)誤。所以在聲明變量后馬上對(duì)其初始化一個(gè)默認(rèn)的值是最簡(jiǎn)單有效的辦法,否則項(xiàng)目大了你找都沒(méi)地方找。代碼存在錯(cuò)誤在debug方式下可能會(huì)忽略而不被察覺(jué)到,如debug方式下數(shù)組越界也大多不會(huì)出錯(cuò),在release中就暴露出來(lái)了,這個(gè)找起來(lái)就比較難了:( 還是自己多加注意吧
    呵呵,就是我犯的問(wèn)題~~
    2. 自定義消息的消息參數(shù)。
     MFC為我們提供了很好的消息機(jī)制,更增加了自定義消息,好處我就不用多說(shuō)了。這也存在debug跟release的問(wèn)題嗎?答案是肯定的。在自定義消息的函數(shù)體聲明時(shí),時(shí)常會(huì)看到這樣的寫法:afx_msg LRESULT OnMessageOwn(); Debug情況下一般不會(huì)有任何問(wèn)題,而當(dāng)你在Release下且多線程或進(jìn)程間使用了消息傳遞時(shí)就會(huì)導(dǎo)致無(wú)效句柄之類的錯(cuò)誤。導(dǎo)致這個(gè)錯(cuò)誤直接原因是消息體的參數(shù)沒(méi)有添加,即應(yīng)該寫成:afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam); (注2)
    3. release模式下不出錯(cuò),但debug模式下報(bào)錯(cuò)。
     這種情況下大多也是因?yàn)榇a書寫不正確引起的,查看MFC的源碼,可以發(fā)現(xiàn)好多ASSERT的語(yǔ)句(斷言),這個(gè)宏只是在debug模式下才有效,那么就清楚了,release版不報(bào)錯(cuò)是忽略了錯(cuò)誤而不是沒(méi)有錯(cuò)誤,這可能存在很大的隱患,因?yàn)槭荄ebug模式下,比較方便調(diào)試,好好的檢查自己的代碼,再此就不多說(shuō)了。
    4. ASSERT, VERIFY, TRACE..........調(diào)試宏
    這種情況很容易解釋。舉個(gè)例子:請(qǐng)?jiān)赩C下輸入ASSERT然后選中按F12跳到宏定義的地方,這里你就能夠發(fā)現(xiàn)Debug中ASSERT要執(zhí)行AfxAssertFailedLine,而Release下的宏定義卻為"#define ASSERT(f) ((void)0)"。所以注意在這些調(diào)試宏的語(yǔ)句不要用程序相關(guān)變量如i++寫操作的語(yǔ)句。VERIFY是個(gè)例外,"#define VERIFY(f) ((void)(f))",即執(zhí)行,這里的作用就不多追究了,有興趣可自己研究:)。
    總結(jié):
     Debug與Release不同的問(wèn)題在剛開(kāi)始編寫代碼時(shí)會(huì)經(jīng)常發(fā)生,99%是因?yàn)槟愕拇a書寫錯(cuò)誤而導(dǎo)致的,所以不要?jiǎng)硬粍?dòng)就說(shuō)系統(tǒng)問(wèn)題或編譯器問(wèn)題,努力找找自己的原因才是根本。我從前就常常遇到這情況,經(jīng)歷過(guò)一次次的教訓(xùn)后我就開(kāi)始注意了,現(xiàn)在我所寫過(guò)的代碼我已經(jīng)好久沒(méi)遇到這種問(wèn)題了。下面是幾個(gè)避免的方面,即使沒(méi)有這種問(wèn)題也應(yīng)注意一下:
    1. 注意變量的初始化,尤其是指針變量,數(shù)組變量的初始化(很大的情況下另作考慮了)。
    2. 自定義消息及其他聲明的標(biāo)準(zhǔn)寫法
    3. 使用調(diào)試宏時(shí)使用后注釋掉
    4. 盡量使用try - catch(...)
    5. 盡量使用模塊,不但表達(dá)清楚而且方便調(diào)試。
    注1:
     debug版初始化成0xcc是因?yàn)?xcc在x86下是一條int 3單步中斷指令,這樣程序如果跑飛了遇到0xcc就會(huì)停下來(lái),這和單片機(jī)編程時(shí)一般將沒(méi)用的代碼空間填入jmp 0000語(yǔ)句是一樣地