明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

調(diào)試Release版本應(yīng)用程序

[摘要]引言如果在您的開發(fā)過程中遇到了常見的錯(cuò)誤,或許您的Release版本不能正常運(yùn)行而Debug版本運(yùn)行無誤,那么我推薦您閱讀本文:因?yàn)椴⒎侨缒胂蟮哪菢,Release版本可以保證您的應(yīng)用程序可以象D...
引言
如果在您的開發(fā)過程中遇到了常見的錯(cuò)誤,或許您的Release版本不能正常運(yùn)行而Debug版本運(yùn)行無誤,那么我推薦您閱讀本文:因?yàn)椴⒎侨缒胂蟮哪菢,Release版本可以保證您的應(yīng)用程序可以象Debug版本一樣運(yùn)行。

如果您在開發(fā)階段完成之后或者在開發(fā)進(jìn)行一段時(shí)間之內(nèi)從來沒有進(jìn)行過Release版本測試,然而當(dāng)您測試的時(shí)候卻發(fā)現(xiàn)問題,那么請(qǐng)看我們的調(diào)試規(guī)則1:

規(guī)則1: 經(jīng)常性對(duì)開發(fā)軟件進(jìn)行Debug和Release版本的常規(guī)測試.

測試Release版本的時(shí)間間隔越長,排除問題的難度越大,至少對(duì)Release版本進(jìn)行每周1次的測試,可以使您在緊湊的開發(fā)周期內(nèi)節(jié)省潛在的排故時(shí)間.

不要隨意刪除Release版本需要的代碼
這點(diǎn)看起來似乎再明顯不過,但卻是開發(fā)人員無意中經(jīng)常犯的錯(cuò)誤,原因在于編譯器編譯Release版本時(shí)候會(huì)主動(dòng)排除在代碼中存在的宏,例如ASSERT和TRACE在Release版本會(huì)自動(dòng)排除,這樣導(dǎo)致的問題是您在這些宏當(dāng)中運(yùn)行的代碼也被隨之刪除,這是非常危險(xiǎn)的事情J,例如:

      ASSERT(m_ImageList.Create(MAKEINTRESOURCE(IDB_IMAGES), 16, 1, RGB(255,255,255)));

這樣的代碼在Debug模式不會(huì)出錯(cuò),圖像列表也自動(dòng)創(chuàng)建了,然而在Release版本呢?后繼使用m_ImageList對(duì)象只會(huì)造成程序的Crash!,因此ASSERT宏中盡量使用邏輯運(yùn)算符作為驗(yàn)證。

規(guī)則 2: 不要將代碼放置在僅在某種編譯選項(xiàng)中執(zhí)行的地方,對(duì)于使用_DEBUG等編譯選項(xiàng)宏內(nèi)部的代碼必須不影響整個(gè)程序的使用.

規(guī)則 3: 不要使用規(guī)則2作為評(píng)判標(biāo)準(zhǔn)來刪除ASSERT宏,ASSERT宏是個(gè)有用的工具,但容易使用錯(cuò)誤.

使Debug編譯模式接近Release模式
如果您的Release版本存在的問題是由代碼被編譯器自動(dòng)排除造成的,那么通過這個(gè)方法您的問題可能會(huì)重現(xiàn).

一些問題的產(chǎn)生可能是由于不同編譯選項(xiàng)之間預(yù)定義符號(hào)造成的,因此您可以更改編譯模式下的預(yù)定義符號(hào),從而使您的Debug模式接近Release模式,觀察錯(cuò)誤是否產(chǎn)生,更改編譯預(yù)定義符號(hào)方法如下:

Alt-F7打開項(xiàng)目設(shè)置,在C++/C 頁面,選擇"General"類別,更改"_DEBUG"符號(hào)為"NDEBUG".
在C++/C 頁面, 選擇"Preprocessor"類別,添加預(yù)定義符號(hào)"_DEBUG"到"Undefined Symbols"欄.
使用"Rebuild All"重新編譯
如果通過上面設(shè)置,您在Release編譯模式下面的問題在Debug模式下重現(xiàn),那么請(qǐng)您依據(jù)以下步驟對(duì)您的代碼進(jìn)行修改:

查找ASSERT排除其中的所有重要執(zhí)行語句,或者將ASSERT修改為VERIFY.
檢查"#ifdef _DEBUG" 內(nèi)所有代碼,排除Release模式使用的代碼.
查找TRACE 排除其中的所有重要執(zhí)行語句. TRACE和ASSERT一樣,僅在Debug模式下編譯.
如果通過上面修改更正了您在Debug模式下的問題,那么您可以重新編譯Release模式,非常有可能您可以解決先前存在的問題!.

錯(cuò)誤的假定造成編譯模式錯(cuò)誤
您是否經(jīng)常性的假定您的變量或者對(duì)象被初試化成某個(gè)指定的值(可能0)?您是否假定你所有關(guān)聯(lián)到的資源在應(yīng)用程序中都存在?這些也是Debug和Release模式下不同問題產(chǎn)生的原因.

規(guī)則 4: 除非您在代碼中對(duì)變量進(jìn)行初始化,否則不能作出如上假定. 包括全局變量,自動(dòng)變量,申請(qǐng)對(duì)象和new對(duì)象.

這種情況還常常發(fā)生在內(nèi)存順序的問題,記得原來使用結(jié)構(gòu)體的時(shí)候?yàn)榱耸褂梅奖,比較兩個(gè)結(jié)構(gòu)體對(duì)象使用memcmp,在Debug版本工作正常,而Release版本計(jì)算出錯(cuò)誤的解,看來的確不能進(jìn)行錯(cuò)誤的假定!

規(guī)則 5: 確保刪除資源的所有引用都被刪除,例如resource.h中的定義.

軟件開發(fā)中,不同編譯版本對(duì)變量和內(nèi)存的初始化是不同的. 如果您假定變量初始化為0,那么在Win9x系統(tǒng)的Release模式下,會(huì)出現(xiàn)異常現(xiàn)象。因此對(duì)所有變量,內(nèi)存顯式清0是較為安全的做法.

如果您引用了已經(jīng)被刪除的資源,您的Debug版本可以正常工作,但是Release版本可能會(huì)crash.

您是否相信編譯器?
編譯器警告級(jí)別和編譯噪音有著相當(dāng)大的關(guān)系.

通過提高編譯器警告級(jí)別可增加程序隱藏問題暴露的機(jī)會(huì).通常設(shè)置警告級(jí)別在"Level 3"或者 "Level 4".編譯并解決所有警告,這是發(fā)布Release版本應(yīng)用程序的一個(gè)很好的建議.這能暴露會(huì)使您的應(yīng)用程序出現(xiàn)問題的很多初始化問題和其它潛在的錯(cuò)誤.

規(guī)則 6: 開始項(xiàng)目之前先將編譯警告級(jí)別設(shè)置在"Level 3" 或者 "Level 4" ,登記代碼之前確保消滅所有警告!.

總結(jié)報(bào)告
編譯模式下的調(diào)試
曾經(jīng)不止一次的聽到一些VC開發(fā)者說Release模式下面不能進(jìn)行調(diào)試,幸運(yùn)的是:通過相應(yīng)設(shè)置,可以在Release模式進(jìn)行調(diào)試,因此那只不過是一個(gè)以訛傳訛的荒謬說法而已.

規(guī)則 7: 當(dāng)前面所有的方法都無效的時(shí)候,在Release模式下面進(jìn)行調(diào)試.

Release模式可以進(jìn)行調(diào)試,第一步是打開符號(hào)表:

Alt-F7打開項(xiàng)目設(shè)置,在C++/C 頁面,選擇"General"類,修改Debug Info setting 為 "Program Database".
在"Link" 頁面,選擇"Generate Debug Info".
"Rebuild All"
這些設(shè)置將允許您在Release模式下保留符號(hào)表,您也可以同時(shí)考慮以下設(shè)置:

調(diào)試Release版本應(yīng)用程序,您可以關(guān)閉優(yōu)化選項(xiàng).
如果在Release模式下面不能設(shè)置斷點(diǎn),添加指令"__asm {int 3}" 可以是您的應(yīng)用程序在改行停止(確定在發(fā)布應(yīng)用程序時(shí)候排除這些代碼).
在Release模式進(jìn)行調(diào)試的幾個(gè)限制.

最大的問題在于您不能跟蹤到MFC函數(shù)內(nèi)部,原因在于Release版本的MFC動(dòng)態(tài)鏈接庫不包含調(diào)試信息和符號(hào)表.
同上,想要調(diào)試調(diào)用的dll,您必須給它們?nèi)考由险{(diào)試信息和符號(hào)表.
編譯器生成了錯(cuò)誤的代碼?
或許有的時(shí)候您會(huì)發(fā)現(xiàn)VC++編譯器生成了’問題代碼’,然而坦率的講,人們通常抱怨的太早.您可以在Release模式下面關(guān)閉優(yōu)化選項(xiàng)來進(jìn)行測試.

如果這個(gè)操作解決了您的問題,或許您的編碼習(xí)慣存在問題. 信不信由你, 極其可能在您的編碼中存在模棱兩可的求解或者看起來似乎正確,某些條件下也是正確的情況. 舉個(gè)例子,下面的代碼在Debug模式似乎一切’正!赗elease模式下面卻會(huì)出錯(cuò)!

#include <stdio.h>

int* func1()
{
int retval = 5;
return &retval;
}

int main(int argc, char* argv[])
{
printf("%d\n", *func1());
return 0;
}
我相信大多數(shù)程序員尤其是初學(xué)者容易遇到此類情況的.

規(guī)則 8: 如果關(guān)閉Release模式的優(yōu)化選項(xiàng)可以使您的應(yīng)用程序運(yùn)行正常,而打開優(yōu)化選項(xiàng)則出現(xiàn)問題的化,原因多半在于您的不良編碼習(xí)慣造成的. 這意味著必須仔細(xì)檢查您的代碼,清理出那些錯(cuò)誤的假設(shè),懸空指針等等. 等同的這告訴您,在Debug模式和關(guān)閉優(yōu)化選項(xiàng)的Release模式下您的應(yīng)用程序工作正常全是因?yàn)橄到y(tǒng)隱含的運(yùn)氣,您必須著手更正存在隱患的代碼,否則在日后可能會(huì)造成巨大的損失.

規(guī)則 9: 如果您已經(jīng)徹底檢查了您的代碼,并且沒有發(fā)現(xiàn)問題,那么您最好逐個(gè)打開優(yōu)化選項(xiàng)將產(chǎn)生錯(cuò)誤的原因限制在某個(gè)范圍之內(nèi).

BTW- 以上問題代碼由C++編譯器自動(dòng)檢出. 如果您已經(jīng)遵循 規(guī)則 6 您或許在前面環(huán)節(jié)中已經(jīng)解決了這些問題.

憑我的開發(fā)經(jīng)驗(yàn),編譯器極少會(huì)產(chǎn)生錯(cuò)誤的代碼(當(dāng)然要注意接口程序邊界對(duì)齊的問題).通常在使用模板類時(shí)候VC6編譯器或許會(huì)產(chǎn)生斷言ASSERT錯(cuò)誤,這種情況您只需更新補(bǔ)丁即可解決.

最后的思考
在日常編碼中只需稍微增加一點(diǎn)嚴(yán)格的檢測,便能有效的避免新的Debug -v- Release模式問題的產(chǎn)生,以下是我的一些經(jīng)驗(yàn).

1.      取出(check out)需要修改的代碼.

2.      修改代碼,排除所有警告,編譯Debug和Release版本.

3.      詳細(xì)測試新代碼,即單步調(diào)試新代碼段之后進(jìn)入工作代碼,確保代碼無誤.

4.      更正所有問題.

5.      確認(rèn)無誤之后將新代碼登記入庫(check in).

6.      對(duì)登記入庫的代碼進(jìn)行全新的編譯,確保新登記代碼與其它代碼融合.

7.      重新詳細(xì)測試代碼.

8.      更正新問題(或許可以發(fā)現(xiàn)登記入庫代碼存在的問題)

嚴(yán)格按照以上步驟,您在設(shè)計(jì)開發(fā)過程中即可解決大量問題,避免在最后發(fā)布應(yīng)用程序時(shí)候產(chǎn)生新的難以定位的問題.

后記
本文是在我的開發(fā)歷程中遇到Release版本應(yīng)用程序發(fā)布,產(chǎn)生錯(cuò)誤的時(shí)候苦苦求索得到的一些經(jīng)驗(yàn),原文來自于codeproject,經(jīng)過本人潤色,改寫成為適合國內(nèi)開發(fā)者的文章,希望能對(duì)大家有用,謝謝!