• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++樂園

            C/C++ 交流

              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
              12 隨筆 :: 18 文章 :: 14 評論 :: 0 Trackbacks
            經常在?CSDN?上看見有人問?Debug?運行正常但?Release?失敗的問題。以往的討論往往是經驗性的,并沒有指出會這樣的真正原因是什么,要想找出真正的原因通常要憑運氣。最近我看了一些這方面的書,又參考了?CSDN?上的一些帖子,然后深入研究了一下關于二者的不同。以下是我的一些體會,拿來與大家共享。?--------------------------------------?本文主要包含如下內容:
            ?1.?Debug?和?Release?編譯方式的本質區別?
            2.?哪些情況下?Release?版會出錯?
            2.?怎樣"調試"?Release?版的程序?--------------------------------------?
            關于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?等選項造成錯誤的情況比較少,而且他們的效果顯而易見,比較容易發現。?三、怎樣"調試"?Release?版的程序?遇到?Debug?成功但?Release?失敗,顯然是一件很沮喪的事,而且往往無從下手。如果你看了以上的分析,結合錯誤的具體表現,很快找出了錯誤,固然很好。但如果一時找不出,以下給出了一些在這種情況下的策略。?1.?前面已經提過,Debug?和?Release?只是一組編譯選項的差別,實際上并沒有什么定義能區分二者。我們可以修改?Release?版的編譯選項來縮小錯誤范圍。如上所述,可以把?Release?的選項逐個?注:那篇文章到此就完了,好像還有一些沒了。

            在VC中當整個工程較大時,軟件時常為出現在DEBUG狀態下能運行而在RELEASE狀態下無法運行的情況。由于開發者通常在DEBUG狀態下開發軟件,所以這種情況時常是在我們辛苦工作一兩個月后,滿懷信心的準備將軟件發行時發生。為了避免無謂的損失,我們最好進行以下的檢查:?1、時常測試軟件的兩種版本。?2、不要輕易將問題歸結為DEBUG/RELEASE問題,除非你已經充分對兩種版本進行了測試。?3、預處理的不同,也有可能引起這樣的問題。出現問題的一種可能性是在不同版本的編譯間定義了不同的預處理標記。請對你的DEBUG版本的軟件試一下以下改動:?在"Project?Setting(ALT-F7)"?中的C/C++項中設置目錄(category)為"General",并且改動"_DEBUG"定義為"NDEBUG".?設置目錄為"Preprocessor"并且添加定義"_DEBUG到"Undefined?Symbols"輸入框.?選擇Rebuild?ALL,重新編譯.?如果經過編譯的程序產生了問題,請對代碼進行如下改動:?將ASSERT()?改為?VERIFY().?找出定義在"#ifdef?_DEBUG"中的代碼,如果在RELEASE版本中需要這些代碼請將他們移到定義外。?查找TRACE(...)中代碼,因為這些代碼在RELEASE中也不被編譯。?所以請認真檢查那些在RELEASE中需要的代碼是否并沒有被便宜。?4、變量的初始化所帶來的不同,在不同的系統,或是在DEBUG/RELEASE版本間都存在這樣的差異,所以請對變量進行初始化。?5、是否在編譯時已經有了警告?請將警告級別設置為3或4,然后保證在編譯時沒有警告出現.?6、是否改動了資源文件.?7、此外對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"優化選項并未被完全支持,因此這將會引起內存錯誤并導致程序崩潰。
            posted on 2007-02-26 16:57 小不懂^_^ 閱讀(4000) 評論(1)  編輯 收藏 引用

            評論

            # re: Debug 運行正常但 Release 失敗的問題,Debug 和 Release 編譯方式的本質區別 2015-04-08 16:41 88876
            到處都是復制的內容  回復  更多評論
              

            久久久噜噜噜久久中文福利| 香蕉久久夜色精品国产2020| www.久久精品| 国产精品久久久久久搜索| 久久久综合九色合综国产| 色天使久久综合网天天| 国产精品一区二区久久国产| 久久久久综合中文字幕| 亚洲国产精品成人久久| 日韩电影久久久被窝网| 99久久精品国产免看国产一区| 久久精品免费网站网| 久久一日本道色综合久久| 久久久久久久久久免免费精品| 久久综合狠狠综合久久综合88| 日本久久中文字幕| 亚洲国产精品人久久| 久久超碰97人人做人人爱| 国产精品久久久久久久久软件| 人人狠狠综合久久亚洲婷婷| 亚洲AV无码久久寂寞少妇| 中文精品99久久国产 | 国产精品久久久久久影院| 久久人人青草97香蕉| 久久一区二区三区99| 久久美女网站免费| 久久久无码精品亚洲日韩按摩 | 99久久综合国产精品免费| 亚洲天堂久久精品| 久久中文字幕一区二区| 国产午夜久久影院| 久久精品国产只有精品2020| 成人资源影音先锋久久资源网| 亚洲午夜无码久久久久| 久久精品国产男包| 亚洲精品乱码久久久久66| 中文字幕无码免费久久| 色诱久久久久综合网ywww| 久久久国产精品亚洲一区| 国产精品久久久久久久久| 国产精品gz久久久|