標籤:
關於Debug和Release的區別之討論本文主要包含如下內容:
1. Debug 和 Release 編譯方式的本質區別
2. 哪些情況下 Release 版會出錯
2. 怎樣“調試” 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:
2. 最佳化:這類錯誤主要有以下幾種:
(1) 幀指標(Frame Pointer)省略(簡稱 FPO ):在函數調用過程中,所有調用資訊(返回地址、參數)以及自動變數都是放在棧中的。若函數的聲明與實現不同(參數、傳回值、調用方式),就會產生錯誤————但Debug 方式下,棧的訪問通過 EBP 寄存器儲存的地址實現,如果沒有發生數組越界之類的錯誤(或是越界“不多”),函數通常能正常執行;Release 方式下,最佳化會省略 EBP 棧基址指標,這樣通過一個全域指標訪問棧
就會造成返回地址錯誤是程式崩潰。C++ 的強型別特效能檢查出大多數這樣的錯誤,但如果用了強制類型轉換,就不行了。你可以在 Release 版本中強制加入 /Oy- 編譯選項來關掉幀指標省略,以確定是否此類錯誤。
(2) volatile 型變數:volatile 告訴編譯器該變數可能被程式之外的未知方式修改(如系統、其他進程和線程)。
(3) 變數最佳化:最佳化程式會根據變數的使用方式最佳化變數。例如,函數中有一個未被使用的變數,在 Debug 版中它有可能掩蓋一個數組越界,而在 Release 版中,這個變數很可能被最佳化調,此時數組越界會破壞棧中有用的資料。當然,實際的情況會比這複雜得多。
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 控制。
4. /GZ 選項:這個選項會做以下這些事
(1) 初始化記憶體和變數。
(2) 通過函數指標調用函數時,會通過檢查棧指標驗證函式調用的匹配性。(防止原形不匹配)
(3) 函數返回前檢查棧指標,確認未被修改.
三、怎樣“調試” Release 版的程式
1. 前面已經提過,Debug 和 Release 只是一組編譯選項的差別,實際上並沒有什麼定義能區分二者。我們可以修改 Release 版的編譯選項來縮小錯誤範圍。
如上所述,可以把 Release 的選項逐個改為與之相對的 Debug 選項,如 /MD 改為 /MDd、/O1 改為 /Od,或已耗用時間最佳化改為程式大小最佳化。注意,一次只改一個選項,看改哪個選項時錯誤消失,再對應該選項相關的錯誤,針對性地尋找。這些選項在 Project\Settings... 中都可以直接通過列表選取,通常不要手動修改。由於以上的分析已相當全面,這個方法是最有效。
2.你也可以像 Debug 一樣調試你的 Release 版,只要加入偵錯符號。在 Project/Settings... 中,選中 Settings for "Win32 Release",選中 C/C++ 標籤,Category 選General,Debug Info 選 Program Database。再在 Link 標籤 Project options 最後加上 "/OPT:REF" (引號不要輸)。
http://www.csharpwin.com/csharpspace/11311r5154.shtml
關於Debug和Release的區別 (VS C#)