標籤:visual studio c++ debug
提要
最近用Visual Studio用的比較多,雖然慢了點,但是用著熟了感覺還是不錯的,特別是2013裡面的自動格式化代碼,對我這種代碼整潔強迫症患者真是莫大的協助。
但是,今天這個坑摸了差不多一天才出來。
環境:Win8.1 64bit Visual Studio 2013 Qt5.3
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 並沒有本質的界限,他們只是一組編譯選項的集合,編譯器只是按照預定的選項行動。事實上,我們甚至可以修改這些選項,從而得到最佳化過的調試版本或是帶跟蹤語句的發布版本。
運行結果不同的原因
debug跟release在初始設定變數時所做的操作是不同的,debug是將每個位元組位都賦成0xcc, 而release的賦值近似於隨機。如果你的程式中的某個變數沒被初始化就被引用,就很有可能出現異常:用作控制變數將導致流程導向不一致;用作數組下標將會使程式崩潰;更加可能是造成其他變數的不準確而引起其他的錯誤。所以在聲明變數後馬上對其初始化一個預設的值是最簡單有效辦法,否則項目大了你找都沒地方找。代碼存在錯誤在debug方式下可能會忽略而不被察覺到。debug方式下數組越界也大多不會出錯,在release中就暴露出來了,這個找起來就比較難了。
我遇到的問題
我這裡遇到的一個問題是向記憶體申請一段記憶體來儲存圖片的像素值,按ARGB格式來存,即alpha通道1bit,red通道1bit,green通道1bit,blue通道1bit,則一個像素用4個自己來表示。
int length = uiCols * uiRows * bytesPerPixel;unsigned char* m_arpBGRABuffers = new unsigned char[length];//Save RGB value to buffer
最後儲存在QImage中用來顯示。
在Debug模式下,顯示正確,但是有點灰,Release模式下什麼都不顯示。
最後定位到這個記憶體申請的位置,列印出記憶體的值,發現Debug模式下數組都被賦值為205,release模式下全部被賦值為0.
那麼問題就來了,為神馬是205!?
趕緊股溝 visual studio 205。
發現在cplusplus上,有個哥們遇到了類似的問題
struct COLOR{ unsigned char R; unsigned char G; unsigned char B;};int main(){ COLOR * color; color = new COLOR[5]; cout << (int)color[3].G //Default value of a color part....(right?) return 0;}
The above, for SOME REASON, returns a value of 205.
205!? Why!?! Every R,G, and B of every COLOR in the array is set to 205!!!
Please give me an explanation...
他需要一個解釋。
It is peculiarity of the Microsoft product(s):
if you declare a variable say for example:
int a then if it not initialised and you run the program then in the debugger it will show a value as follows:
char type will be 0xcc (decimal 204)
short will be 0xcccc
int will be 0xcccccccc
and so on.
If you create a variable/struct using new then if you run the program but have not initialised the variable/structure values
then you will see in the debugger:
char type will be 0xcd (decimal 205) ******
short will be 0xcdcd
int will be 0xcdcdcdcd
and so on.
An unitialised pointer will show as 0xcccccccc
I believe it really does put those values in - because if you try to cout an uninitialised variable and ignore the ‘Unitialised variable error dialog box‘
then you really will see those values on the screen.
這下明白了吧...
之所以release模式下不顯示,因為alpha通道被賦值為0了,之所以debug模式下會有點灰,是因為alpha通道被賦值為205(完全不透明是255)。
解決方案,都賦初值:
int length = uiCols * uiRows * bytesPerPixel;char * m_arpBGRABuffers = new unsigned char[length];//Set ALL chinnal to 255for (int i = 0; i < length; i++){m_arpBGRABuffers[iCamera][i] = 255;}
這下整個世界都清晰了。對比一下:
debug模式下灰灰的圖片
Release 模式下將alpha設為255後的圖片
總結
所有類成員在建構函式中都賦好初值,不要相信和依賴編譯器的行為。
動態申請記憶體的變數,申請完記憶體之後馬上賦初值。
Visual Studio中Debug和Realse版本編譯的結果不同