標籤:use assert 方便 adc dll nec cti 寄存器 異常
0 VC++ 常見的記憶體異常值
|
* 0xcccccccc : Used by Microsoft‘s C++ Debugging runtime library to mark uninitialised stack memory
* 0xcdcdcdcd : Used by Microsoft‘s C++ Debugging runtime library to mark uninitialised heap memory
* 0xfeeefeee : Used by Microsoft‘s HeapFree() to mark freed heap memory
* 0xabababab : Used by Microsoft‘s HeapAlloc() to mark "no man‘s land" guard bytes after allocated heap memory
* 0xabadcafe : A startup to this value to initialize all free memory to catch errant pointers
* 0xbaadf00d : Used by Microsoft‘s LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory
* 0xbadcab1e : Error Code returned to the Microsoft eVC Debugger when connection is severed to the Debugger
* 0xbeefcace : Used by Microsoft .NET as a magic number in resource files |
以上異常值,比較常見的為前三種:
對於0xcccccccc和0xcdcdcdcd,在 Debug 模式下,VC 會把未初始化的棧記憶體上的指標全部填成 0xcccccccc ,當字串看就是 “燙燙燙燙……”;會把未初始化的堆記憶體上的指標全部填成 0xcdcdcdcd,當字串看就是 “屯屯屯屯……”。那麼調試器為什麼要這麼做呢?VC的DEBUG版會把未初始化的指標自動初始化為0xcccccccc或0xcdcdcdcd,而不是就讓取隨機值,那是為了方便我們偵錯工具,如果野指標的初值不確定,那麼每次調試同一個程式就可能出現不一樣的結果,比如這次程式崩掉,下次卻能正常運行,這樣顯然對我們解bug是非常不利的,所以自動初始化的目的是為了讓我們一眼就能確定我們使用了未初始化的野指標了。
對於0xfeeefeee,是用來標記堆上已經釋放掉的記憶體。注意,如果指標指向的記憶體被釋放了,變數本身的地址如未做改動,還是之前指向的記憶體的地址。如果該指標是一個類的指標,並且類中包含有指標變數,則記憶體被釋放後(對於C++類,通常是執行delete操作),類中的指標變數就會被賦值為0xfeeefeee。如果早調試代碼過程中,發現有值為0xfeeefeee的指標,就說明對應的記憶體被釋放掉了,我們的代碼已經出問題了。
在此,就有一個關於VC 中 Debug和Release模式下的變數初始化問題
大家都知道,Debug跟Release在初始設定變數時所做的操作是不同的,Debug是將每個位元組位都賦成0xcc,而Release的賦值近似於隨機(我想是直接從記憶體中分配的,沒有初始化過)。這樣就明確了,如果你的程式中的某個變數沒被初始化就被引用,就很有可能出現異常:用作控制變數將導致流程導向不一致;用作數組下標將會使程式崩潰;更加可能是造成其他變數的不準確而引起其他的錯誤。所以,在聲明變數後馬上對其初始化一個預設的值是最簡單有效辦法,否則項目大了你找都沒地方找。代碼存在錯誤在Debug方式下可能會忽略而不被察覺到,如Debug方式下數組越界也大多不會出錯,在 Release中就暴露出來了,這個找起來就比較難了。
1 VC++ 之Debug運行正常,Release運行崩潰
I、記憶體配置問題
1.變數未初始化。
在Debug中會自動給變數初始化,而在Release中則不會。所以:儘可能的給變數、類或結構初始化(很重要!)。
2.資料溢出的問題
如:
char buffer[10];
int counter;
lstrcpy(buffer, "abcdefghik");
如果您使用了strcpy(),lstrcpy() 等函數請注意檢查。
在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(pNewObj = new CMyClass);
pNewObj->MyFunction();
這種時候Release版本中的pNewObj不會分配到空間所以執行到下一個語句的時候程式會報該程式執行了非法操作的錯誤。這時可以用 VERIFY
III.參數問題:
自訂訊息的處理函數,必須定義如下:
afx_msg LRESULT OnMyMessage(WPARAM, LPARAM);
傳回值必須是HRESULT型,否則Debug會過,而Release出錯
IV. 記憶體配置
保證資料建立和清除的統一性:如果一個DLL提供一個能夠建立資料的函數,那麼這個DLL同時應該提供一個函數銷毀這些資料。資料的建立和清除應該在同一個層次上。
V.DLL的災難
人們將不同版本DLL混合造成的不一致性形象的稱為 “動態串連庫的地獄“(DLL Hell)如果你的程式使用你自己的DLL時請注意:
1.不能將Debug和Release版的DLL混合在一起使用。Debug都是Debug版,Release版都是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工程都進行改動
VC++ 之常見記憶體異常值