日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

VC++调试技巧学习总结

發布時間:2025/4/14 c/c++ 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 VC++调试技巧学习总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

VC6.0調試方法

有時候,我們編寫好一個程序后,希望通過調試來知道變量值的變化情況,下面我和大家分享一下怎么利用VC6.0來查看變量值變化情況。


工具/原料
VC6.0軟件、待測試程序
方法/步驟
1
打開你要調試代碼的工作空間。
2
按快捷鍵F5或點擊以下圖片上標記的圖標進入調試模式。


3
打開調試工具條,一般情況下當你按F5鍵后會自動彈出,如果沒有彈出的話,右擊工具欄空白處,會彈出下圖,選中調試,就會出現調試工具條。


4
接下來,在監視窗口中添加你要監視數據變化的變量。


5
按F11逐語句的調試代碼,如果某一語句是一函數,你不希望進入該函數時,F10逐過程來查看,在代碼的調試過程中,通過監視窗口查看變量值的變化,從而確定代碼是否有問題。


6
如果希望跳出某一函數時,按快捷鍵Shift+F11,或者直接點擊調試工具條上的按鈕就可以跳出該函數了。


7
如果只是希望調試某一部分代碼的話,可以設置斷點來調試,調試方法如上,只是在要調試的代碼之間用斷點來分開。設置斷點時,光標放在你要設置斷點的那行,按F9或點擊編譯微型條上面的類似


手狀的按鈕即可。
========

VC 6.0 調試技巧(二)

http://blog.csdn.net/dddd0216/article/details/51330163


1. Restart (Ctrl+shift+F5 ): 此debugger功能將從程序的開始(第一有效行)處全速執行,而不是從當前所跟蹤的位置開始調試,這時所有變量的當前值都將被丟棄,debugger 會自動停在程序的main()開始


處.這時如果選擇Step Over(F10)就可以逐步執行main()函數了.
2. Stop Debugging (Shift+F5 ):此debugger功能將終止(所有)調試,并返回到常規編輯狀態.?
3. Break (此功能常常在遇到調用函數的語句時可見 .): 此功能將在調試過程中的debugger當前位置掛起程序的執行,然后就可以在調試狀態一修改程序的代碼,接著可以用Apply Code Changes(Alt


+F10)來應用修改的代碼到正在調試的程序當中.如果,當前(需要,待)可以(從DOS 等窗口)輸入值,掛起后將不能再輸入.
4. Apply Code Changes (Alt+F10 ):此功能可以在程序正在調試程序過程中應用(掛起)修改后的源代碼.如,選擇Break功能并修改代碼后,只要選擇Apply Code Changes(Alt+F10)就能將修改后的代碼應


用到正在調試的程序當中.
5. Show Next Statement (Alt+Num* ):此功能將顯示程序代碼的下一條語句,如果源代碼中找不到,則在Disassembly窗口中顯示語句. 當在Disassembly窗口中顯示時,可以單擊Disassembly 返回到源代


碼窗口.
6. Step Into (F11 ):此功能可以單步進入到在調試過程中所跟蹤的調用函數的語句的函數內部.如,當前語句是"d.Display()",?
選擇Step Into(F11)后,Debugger將進入Display()函數內部并停在Display()函數內部的第一條語句上.(此時, 就可以Step Over(F10)對Display()函數進行單步調試了.)
7. Step Over (F10 ):此功能可以單步對所在函數單步調試,如果調試的語句是一個調用函數的語句時, Debugger將全速執行所調用的函數,單步(一步)通過所調用的函數,Debugger停該調用語句的下一條


語句上.
8. Step Out (Shift+F11 ):此功能將使Debugger切換回全速執行到被調用函數結束,并停在該函數調用語句的下一條語句上. 當確定所調用的函數沒有問題時可以用這個功能全速執行被調用函數.
9. Run to Cursor (Ctrl+F10 ):此功能將全速執行到包含插入點光標所在的行,可以作為在插入點光標處設置常規斷點的一種選擇. 注意,當光標處不是一個有效的執行語句時此功能將不起作用.
10. Go (F5 ):此功能將全速執行程序直到遇到一個斷點或程序結束,或直到程序暫停等待用戶輸入. 注意,此功能最能有效的調試循環,常將斷點設置在循環體內,重復的按F5全速執行循環體可以測試循環過


程中的產生的變化.
11.Step Into Specific Function:此功能可以可以單步通過程序中的指令,并進入指定的函數調用,此功能對于函數的嵌套層不限.
??
調試常用快捷鍵
單步進入 ? ? ? ? ? ? ? F11
?
單步跳過 ? ? ? ? ? ? ?F10
?
單步跳出 ? ? ? ? ? ? ?SHIFT+F11
?
運行到光標 ? ? ? ? ? CTRL+F10
?
開關斷點 ? ? ? ? ? ? ?F9
?
清除斷點 ? ? ? ? ? ? ?CTRL+SHIFT+F9
?
Breakpoints(斷點管理) ? ? ? ? ? ? ?CTRL+B 或ALT+F9
?
GO ? ? ? ? ? ? ? ? ? ? ? F5
?
Compile(編譯,生成.obj文件) ? ? ? CTRL+F7
?
Build(組建,先Compile生成.obj再Link生成.exe) ? ? ? ? ? ? ?F7
?
From 《Visual C++ Debugger》
?
From 《visual C++ 6.0開發工具與調試》
1、 ? ? ? ? ?如何快速地規范代碼縮進格式
選中所需要規范的代碼,按shift+F8
2、 ? ? ? ? ?如何在Release狀態下進行調試
Project->Setting=>ProjectSetting對話框,選擇Release狀態。C/C++標簽中的Category選General,Optimizations選Disable(Debug),
Debut info選Program Database。在Link標簽中選中Generate debug info復選框。
?
注:只是一個介乎Debug合Release的中間狀態,所有的ASSERT、VERIFY都不起作用,函數調用方式已經是真正的調用,而不查表,
但是這種狀態下QuickWatch、調用隊列跟蹤功能仍然有效,和Debug版一樣。
?
3、 ? ? ? ? ?Release和Debug有什么不同。
Release版稱為發行版,Debug版稱為調試版。
Debug中可以單步執行、跟蹤等功能,但生成的可執行文件比較大,代碼運行速度較慢。Release版運行速度較快,可執行文件較小,
但在其編譯條件小無法執行調試功能。
Release的exe文件鏈接的是標準的MFC DLL(Use MFC in a shared or static dll),比如MFC42.DLL。這些DLL在安裝Windows的時候,
已經配置,所以這些程序能夠在沒有安裝Visual C++ 6.0的機器上運行。而Debug版本的exe鏈接了調試版本的MFC DLL文件,如MFC42D.DLL。
在沒有安裝Visual C++6.0的機器上不能運行,因為缺MFC42D.DLL等,除非選擇use static dll when link。
?
4、 ? ? ? ? ?ASSERT和VERIFY有什么區別
ASSERT里面的內容在Release版本中不編譯,VERIFY里面的內容仍然翻譯,但不再判斷真假。所以后者更安全一點。
例如ASSERT(file.Open(strFileName))。
一旦到了Release版本中,這一行就忽略了,file根本就不Open()了,而且沒有任何出錯的信息。如果用VERIFY()就不會有這個問題。
?
5、 ? ? ? ? ?Workspace和Project之間是什么樣的關系
每個Workspace可以包括幾個project,但只有一個處于Active狀態,各個project之間可以有依賴關系,在project的Setting..中可以設定,
比如那個Active狀態的project可以依賴于其他的提供其函數調用的靜態庫。
?
6、 ? ? ? ? ?如何在非MFC程序中使用ClassWizard
在工程目錄下新建一個空的.RC文件,然后加入到工程中就可以了。
?
7、 ? ? ? ? ?如何設置斷點
按F9在當前光標處增加一個斷點和取消一個斷點。
另外,在編輯狀態下,按Ctrl+B組合鍵,彈出斷點設置對話框。然后單擊【Condition…】按鈕彈出設置斷點條件的對話框進行設置。
?
8、 ? ? ? ? ?在編輯狀態下發現成員變量或函數不能顯示提示是如何打開顯示功能
這似乎是目前這個Visual C++ 6.0版本的一個bug,可按如下步驟使其正常,如再出現,可如法炮制:
(1) ? ? ? ? ? ? 關閉Project
(2) ? ? ? ? ? ? 刪除"工程名.ncb"文件
(3) ? ? ? ? ? ? 重新打開工程
?
9、 ? ? ? ? ?如何將一個通過ClassWizard生成的類徹底刪除
首先在工作區的FileView中選中該類的.h和.cpp文件,按delete刪除,然后在文件管理器中將這兩個文件刪除,再運行ClassWizard,
這時出現是否移走該類的提示,選擇remove就可以了。
?
10、 ? ? 如何將再workspace中消失的類找出來
打開該類對應的頭文件,然后將其類名隨便改一下,這個時候工作區就會出現新的類,再將這個類改回原來的名字就可以了。
?
11、 ? ? 如何清除所有的斷點
菜單【Edit】->【Breakpoints…】,打開"Breakpoints"對話框,單擊【Remove All】按鈕即可。
快捷鍵是"Ctrl + Shift + F8"。
?
12、 ? ? 如何再ClassWizard中選擇未列出的信息
打開"ClassWizard"對話框,然后切換到"Class Info"頁面。改變"Message filter",如選擇"Window","Message"頁面就會出現Window的信息。
?
13、 ? ? 如何檢測程序中的括號是否匹配
把光標移動到需要檢測的括號前面,按快捷鍵"Ctrl + ]"。如果括號匹配正確,光標就跳到匹配的括號處,否則光標不移動,
并且機箱喇叭還會發出一聲警告。
?
14、 ? ? 如何查看一個宏(或變量、函數)的定義
把光標移動到要查看的一個宏上,就比如說最常見的DECLARE_MAP_MESSAGE上按一下F12(或右鍵菜單中的相關菜單),
如果沒有建立瀏覽文件,就會出現提示對話框,按【確定】按鈕,然后就會跳到該宏(或變量、函數)定義的地方。
?
15、 ? ? 如何添加Lib文件到當前工程
單擊菜單【Project】->【Settings…】彈出"Project Setting"對話框,切換到"Link"標簽頁,在"Object/library modules"處輸入Lib文件名稱,
不同的Lib之間用空格格開。
?
16、 ? ? 如何快速刪除項目下的Debug文件夾中臨時文件
在工作區的FileView視圖中選中對應的項目,單擊右鍵彈出菜單,選擇【Clean(selection only)】菜單即可。
?
17、 ? ? 如何快速生成一個現有工程除了工程名外完全相同的新工程。
在新建工程的"New"對話框中選擇"Custom Appwizard"項,輸入新工程的名字,單擊【OK】按鈕。出現"Custom AppWizard"項,
輸入新工程的名字,單擊【OK】按鈕。出現"Custom AppWizard-Step 1 of 2"對話框,選擇"An existing Project"項,單擊【Next】按鈕。
出現"Custom AppWizard-Step 2 of 2"對話框,選擇現有工程的工程文件名,最后單擊【Finish】按鈕。編譯后就生成一個與現有工程相同
但可以重新取名的工程AppWizard。
現在就可以項用MFC AppWizard一樣用這個定制的向導。如果不想用了,可以在Visual C++ 6.0安裝目錄下Common/MSDev98/Template目錄
中刪除該Wizard對應的.awx和.pdb文件。
?
18、 ? ? 如何解決Visual C++ 6.0不正確連接的問題
情景:明明之間改動了一個文件,卻要把整個項目全部重新編譯鏈接一次。剛剛鏈接好,一運行,有提示重新編譯鏈接一次。
這是因為出現了未來文件(修改時間和創建時間比系統時間晚)的緣故。可以這樣處理:找到工程文件夾下的debug目錄,
將創建和修改時間都比系統時間的文件全部刪除,然后再從新"Rebuild All"一次。
?
19、 ? ? 引起LNK2001的常見錯誤都有哪些
遇到的LNK2001錯誤主要為:unresolved external symbol "symbol"
如果鏈接程序不能在所有的庫和目標文件內找到所引用的函數、變量或標簽,將產生此錯誤信息。
一般來說,發生錯誤的原因有兩個:一時所引用的函數、變量不存在,拼寫不正確或者使用錯誤;其次可能使用了不同版本的鏈接庫。
一下是可能產生LNK2001錯誤的原因:
<1>由于編碼錯誤導致的LNK2001錯誤
1.不相匹配的程序代碼或模塊定義(.DEF)文件導致LNK2001。例如,如果在C++源文件了內聲明了一變量"var1",?
卻視圖在另一個文件內以變量"var1"訪問改變量。
(2) ? ? ? ? ? ? 如果使用的內聯函數是在.cpp文件內定義的,而不是在頭文件內定義將導致LNK2001錯誤。
(3) ? ? ? ? ? ? 調用函數是如果所用的參數類型頭函數聲明是的類型不符將會產生LNK2001錯誤。
(4) ? ? ? ? ? ? 視圖從基類的構造函數或析構函數中調用虛擬函數時將會導致LNK2001錯誤。
(5) ? ? ? ? ? ? 要注意函數和變量的可公用性,只有全局變量、函數時可公用的。靜態函數和靜態變量具有相同的使用范圍限制。
當試圖從文件外部方位任何沒有在該文件內聲明的靜態變量時將導致編譯錯誤或LNK2001錯誤。
<2>由于編譯和聯機的設置而造成的LNK2001錯誤
1.如果編譯時使用的時/NOD(/NODERAULTLIB)選項,程序所需要的運行庫和MFC時將得到又編譯器寫入目標文件模塊,?
但除非在文件中明確包含這些庫名,否則這些庫不會北鏈接進工程文件。這種情況下使用/NOD將導致LNK2001錯誤
2.如果沒有為wWinMainCRTStartup設定程序入口,在使用Unicode和MFC時講的到?
"unresolved external on _WinMain@16 "的LNK2001錯誤信息。
3.使用/MD選項編譯時,既然所有的運行庫都被保留在動態鏈接庫之內,源文件中對"func"的引用,?
在目標文件里即對"__imp__func"的引用。如果試圖使用靜態庫LIBC.LIB或LIBCMT.LIB進行鏈接,將在__imp__func上發生LNK2001錯誤。如果不使用/MD選項編譯,在使用MSVCxx.LIB鏈接時也會發


生LNK2001錯誤。
(4) ? ? ? ? ? ? 使用/ML選項編譯時,如用LIBCMT.LIB鏈接回在_errno上發生LNK2001錯誤。
(5) ? ? ? ? ? ? 當編譯調試版的應用程序時,如果采用發行版模態庫進行鏈接也會產生LNK2001錯誤;同樣,
使用調試版模態庫鏈接發行版應用程序時也會產生相同的錯誤。
(6) ? ? ? ? ? ? 不同版本的庫和編譯器的混合使用也能產生問題,因為新版的庫里可能包含早先的版本沒有的符號和說明。
(7) ? ? ? ? ? ? 在不同的模塊中使用內聯和非內聯的編譯選項能夠導致LNK2001錯誤。如果創建C++庫時打開了
函數內聯(/Ob1或/Ob2),但是在描述該函數的相應頭問卷安里卻關閉了函數內聯(沒有inline關鍵字),
只是將得到錯誤信息。為避免該問題的發生,應該在相應的頭文件中用inline關鍵字標志為內聯函數。
(8) ? ? ? ? ? ? 不正確的/SUBSYSTEM或ENTRY設置也能導致LNK2001錯誤。
?
20、 ? ? 如何調試一個沒有源碼的exe文件調用的dll
在Visual C++ 6.0中,進入"Project Setting"對話框然后選擇Debug標簽頁。通常Visual Studio默認"executable for debug session"為可執行文件名,
但可以將他改成任何你想要的程序。甚至可以指定不同的工作目錄以及傳遞參數到你的程序。這個技術常用來調試Dlls、名字空間擴展、
COM對象和其他從某些EXE以及從第三方的EXE中調用的plug-in程序。
?
21、 ? ? Visual C++ 6.0工程中的項目文件都表示什么。
.opt:工程關于開發化境的參數文件。如工具條位置等信息。
.aps(AppStudio File)資源輔助文件,二進制格式,一般不用去管他。
.clw:ClassWizard信息文件,實際上是INI文件格式,又興趣可以研究一下。有時候ClassWizard出了問題,手工修改CLW文件可以解決。
如果此文件不存在的話,每次用ClassWizard的時候回提示是否重建。
.dsp(DevelopStudio Project):項目文件,文本格式,不過不熟悉的或不要手工修改。
.dsw(DevelopStudio Workspace):是工作區文件,其他特點和.dsp差不多。
.plg:是編譯信息文件,編譯時的error和warning信息文件(實際上時一個html文件),一般用處不大。在單擊菜單【Tool】->【Option】
彈出的對話框里面有個選項可以控制這個文件的生成。
.hpj(Help Project):是生成幫助文件的工程,用microsoft Help Compiler可以處理。
.mdp(Microsoft DevStudio Project):是舊版本的項目文件,如果要打開此文件的話,回提示你是否轉換成新的.dsp格式。
.bsc:是用于瀏覽項目信息的,如果用Source Brower的話舊必須又這個文件。如果不用這個功能的話,可以在Project Options里面去掉
Generate Browse Info File,這樣可以加快編譯速度。
.map是執行文件的影像信息記錄文件,除非對系統底層,這個文件一般用不著。
.pch(Pre-Compiled File):是與編譯文件,可以加快編譯速度,但是文件非常大。
.pdb(Program Database),記錄了程序有關的一些數據和調試信息,在調試的時候可能有用。
.exp:只有在編譯DLL的時候才會生成,記錄了DLL文件的一些信息,一般也沒有用。
.ncb:無編譯瀏覽文件(no compile browser)。當自動完成功能出問題時可以刪除此文件。編譯工程后回自動生成。
========

VC++一些開發心得與調試技巧

http://www.cnblogs.com/maowang1991/p/3572329.html
? ? ?1.如何在Release狀態下進行調試
  Project->Setting=>ProjectSetting對話框,選擇Release狀態。C/C++標簽中的Category選General,Optimizations選Disable(Debug),Debut info選Program Database。在Link標簽中選中


Generate debug info復選框。
  注:只是一個介乎Debug和Release的中間狀態,所有的ASSERT、VERIFY都不起作用,函數調用方式已經是真正的調用,而不查表,但是這種狀態下QuickWatch、調用隊列跟蹤功能仍然有效,


和Debug版一樣。


  2. Release和Debug有什么不同
  Release版稱為發行版,Debug版稱為調試版。
  Debug中可以單步執行、跟蹤等功能,但生成的可執行文件比較大,代碼運行速度較慢。Release版運行速度較快,可執行文件較小,但在其編譯條件下無法執行調試功能。
  Release的exe文件鏈接的是標準的MFC DLL(Use MFC in a shared or static dll)。這些DLL在安裝Windows的時候,已經配置,所以這些程序能夠在沒有安裝Visual C++ 6.0的機器上運行。而


Debug版本的exe鏈接了調試版本的MFC DLL文件,在沒有安裝Visual C++6.0的機器上不能運行,因為缺相應的DLL,除非選擇use static dll when link。


  3. ASSERT和VERIFY有什么區別
  ASSERT里面的內容在Release版本中不編譯,VERIFY里面的內容仍然翻譯,但不再判斷真假。所以后者更安全一點。
  例如ASSERT(file.Open(strFileName))。
  一旦到了Release版本中,這一行就忽略了,file根本就不Open()了,而且沒有任何出錯的信息。如果用VERIFY()就不會有這個問題。


  4.Workspace和Project之間是什么樣的關系
  每個Workspace可以包括幾個project,但只有一個處于Active狀態,各個project之間可以有依賴關系,在project的Setting..中可以設定,比如那個Active狀態的project可以依賴于其他的提供其


函數調用的靜態庫。


  5. 如何在非MFC程序中使用ClassWizard
  在工程目錄下新建一個空的.RC文件,然后加入到工程中就可以了。


  6.如何設置斷點
  按F9在當前光標處增加一個斷點和取消一個斷點。
  另外,在編輯狀態下,按Ctrl+B組合鍵,彈出斷點設置對話框。然后單擊【Condition…】按鈕彈出設置斷點條件的對話框進行設置。


  7.在編輯狀態下發現成員變量或函數不能顯示提示是如何打開顯示功能
  這似乎是目前這個Visual C++ 6.0版本的一個bug,可按如下步驟使其正常,如再出現,可如法炮制:
  (1)關閉Project
  (2)刪除“工程名.ncb”文件
  (3)重新打開工程


  8.如何將一個通過ClassWizard生成的類徹底刪除
  首先在工作區的FileView中選中該類的.h和.cpp文件,按delete刪除,然后在文件管理器中將這兩個文件刪除,再運行ClassWizard,這時出現是否移走該類的提示,選擇remove就可以了。


  9. 如何將在workspace中消失的類找出來
  打開該類對應的頭文件,然后將其類名隨便改一下,這個時候工作區就會出現新的類,再將這個類改回原來的名字就可以了。


  10. 如何清除所有的斷點
  菜單【Edit】->【Breakpoints…】,打開“Breakpoints”對話框,單擊【Remove All】按鈕即可。快捷鍵是“Ctrl + Shift + F9”。


  11. 如何再ClassWizard中選擇未列出的信息
  打開“ClassWizard”對話框,然后切換到“Class Info”頁面。改變“Message filter”,如選擇“Window”,“Message”頁面就會出現Window的信息。


  12. 如何檢測程序中的括號是否匹配
  把光標移動到需要檢測的括號前面,按快捷鍵“Ctrl + ]”。如果括號匹配正確,光標就跳到匹配的括號處,否則光標不移動,并且機箱喇叭還會發出一聲警告。


  13. 如何查看一個宏(或變量、函數)的定義
  把光標移動到要查看的一個宏上,就比如說最常見的DECLARE_MAP_MESSAGE上按一下F12(或右鍵菜單中的相關菜單),如果沒有建立瀏覽文件,就會出現提示對話框,按【確定】按鈕,然后就


會跳到該宏(或變量、函數)定義的地方。


  14. 如何添加Lib文件到當前工程
  單擊菜單【Project】->【Settings…】彈出“Project Setting”對話框,切換到“Link”標簽頁,在“Object/library modules”處輸入Lib文件名稱,不同的Lib之間用空格格開。


  15. 如何快速刪除項目下的Debug文件夾中臨時文件
  在工作區的FileView視圖中選中對應的項目,單擊右鍵彈出菜單,選擇【Clean(selection only)】菜單即可。


  16. 如何快速生成一個現有工程除了工程名外完全相同的新工程
  在新建工程的“New”對話框中選擇“Custom Appwizard”項,輸入新工程的名字,單擊【OK】按鈕。出現“Custom AppWizard”項,輸入新工程的名字,單擊【OK】按鈕。出現“Custom?


AppWizard-Step 1 of 2”對話框,選擇“An existing Project”項,單擊【Next】按鈕。出現“Custom AppWizard-Step 2 of 2”對話框,選擇現有工程的工程文件名,最后單擊【Finish】按鈕。


編譯后就生成一個與現有工程相同但可以重新取名的工程AppWizard。
  現在就可以項用MFC AppWizard一樣用這個定制的向導。如果不想用了,可以在Visual C++ 6.0安裝目錄下Common\MSDev98\Template目錄中刪除該Wizard對應的.awx和.pdb文件。


  17. 如何解決Visual C++ 6.0不正確連接的問題
  情景:明明改動了一個文件,卻要把整個項目全部重新編譯鏈接一次。剛剛鏈接好,一運行,又提示重新編譯鏈接一次。
  這是因為出現了未來文件(修改時間和創建時間比系統時間晚)的緣故。可以這樣處理:找到工程文件夾下的debug目錄,將創建和修改時間都比系統時間的文件全部刪除,然后再從新“Rebuild All


”一次。


  18. 引起LNK2001的常見錯誤都有哪些
  遇到的LNK2001錯誤主要為:unresolved external symbol “symbol”
  如果鏈接程序不能在所有的庫和目標文件內找到所引用的函數、變量或標簽,將產生此錯誤信息。
一般來說,發生錯誤的原因有兩個:一是所引用的函數、變量不存在,拼寫不正確或者使用錯誤;其次可能使用了不同版本的鏈接庫。以下是可能產生LNK2001錯誤的原因:
  <1>由于編碼錯誤導致的LNK2001錯誤
  (1)不相匹配的程序代碼或模塊定義(.DEF)文件導致LNK2001。例如,如果在C++源文件了內聲明了一變量“var1”,卻試圖在另一個文件內以變量“var1”訪問改變量。
  (2)如果使用的內聯函數是在.cpp文件內定義的,而不是在頭文件內定義將導致LNK2001錯誤。
  (3)調用函數時如果所用的參數類型和頭函數聲明時的類型不符將會產生LNK2001錯誤。
  (4)試圖從基類的構造函數或析構函數中調用虛擬函數時將會導致LNK2001錯誤。
  (5)要注意函數和變量的可公用性,只有全局變量、函數是可公用的。靜態函數和靜態變量具有相同的使用范圍限制。當試圖從文件外部方位任何沒有在該文件內聲明的靜態變量時將導致編譯錯誤


或LNK2001錯誤。
  <2>由于編譯和聯機的設置而造成的LNK2001錯誤
  (1)如果編譯時使用的是/NOD(/NODERAULTLIB)選項,程序所需要的運行庫和MFC時將得到又編譯器寫入目標文件模塊,但除非在文件中明確包含這些庫名,否則這些庫不會被鏈接進工程文件。


這種情況下使用/NOD將導致LNK2001錯誤
  (2)如果沒有為wWinMainCRTStartup設定程序入口,在使用Unicode和MFC時將出現“unresolved external on _WinMain@16”的LNK2001錯誤信息。
  (3)使用/MD選項編譯時,既然所有的運行庫都被保留在動態鏈接庫之內,源文件中對“func”的引用,在目標文件里即對“__imp__func”的引用。如果試圖使用靜態庫LIBC.LIB或LIBCMT.LIB進


行鏈接,將在__imp__func上發生LNK2001錯誤。如果不使用/MD選項編譯,在使用MSVCxx.LIB鏈接時也會發生LNK2001錯誤。
  (4)使用/ML選項編譯時,如用LIBCMT.LIB鏈接會在_errno上發生LNK2001錯誤。
  (5)當編譯調試版的應用程序時,如果采用發行版模態庫進行鏈接也會產生LNK2001錯誤;同樣,使用調試版模態庫鏈接發行版應用程序時也會產生相同的錯誤。
  (6)不同版本的庫和編譯器的混合使用也能產生問題,因為新版的庫里可能包含早先的版本沒有的符號和說明。
  (7)在不同的模塊中使用內聯和非內聯的編譯選項能夠導致LNK2001錯誤。如果創建C++庫時打開了函數內聯(/Ob1或/Ob2),但是在描述該函數的相應頭文件里卻關閉了函數內聯(沒有inline關鍵字


),只是將得到錯誤信息。為避免該問題的發生,應該在相應的頭文件中用inline關鍵字標志為內聯函數。
  (8)不正確的/SUBSYSTEM或ENTRY設置也能導致LNK2001錯誤。


  19. 如何調試一個沒有源碼的exe文件調用的dll
  在Visual C++ 6.0中,進入“Project Setting”對話框然后選擇Debug標簽頁。通常Visual Studio默認“executable for debug session”為可執行文件名,但可以將他改成任何你想要的程序。


甚至可以指定不同的工作目錄以及傳遞參數到你的程序。這個技術常用來調試Dlls、名字空間擴展、COM對象和其他從某些EXE以及從第三方的EXE中調用的plug-in程序。


20. Visual C++ 6.0工程中的項目文件都表示什么
  .opt:工程關于開發環境的參數文件。如工具條位置等信息。
  .aps(AppStudio File)資源輔助文件,二進制格式,一般不用去管它。
  .clw:ClassWizard信息文件,實際上是INI文件格式,有興趣可以研究一下。有時候ClassWizard出了問題,手工修改CLW文件可以解決。如果此文件不存在的話,每次用ClassWizard的時候回提


示是否重建。
  .dsp(DevelopStudio Project):項目文件,文本格式,不過不熟悉的不要手工修改。
  .dsw(DevelopStudio Workspace):是工作區文件,其他特點和.dsp差不多。
  .plg:是編譯信息文件,編譯時的error和warning信息文件(實際上是一個html文件),一般用處不大。在單擊菜單【Tool】->【Option】彈出的對話框里面有個選項可以控制這個文件的生成。
  .hpj(Help Project):是生成幫助文件的工程,用microsoft Help Compiler可以處理。
  .mdp(Microsoft DevStudio Project):是舊版本的項目文件,如果要打開此文件的話,會提示你是否轉換成新的.dsp格式。
  .bsc:是用于瀏覽項目信息的,如果用Source Brower的話就必須有這個文件。如果不用這個功能的話,可以在Project Options里面去掉Generate Browse Info File,這樣可以加快編譯速度。
  .map是執行文件的映象信息記錄文件,除非對系統底層,這個文件一般用不著。
  .pch(Pre-Compiled File):是與編譯文件,可以加快編譯速度,但是文件非常大。
  .pdb(Program Database):記錄了程序有關的一些數據和調試信息,在調試的時候可能有用。
  .exp:只有在編譯DLL的時候才會生成,記錄了DLL文件的一些信息,一般也沒有用。
  .ncb:無編譯瀏覽文件(no compile browser)。當自動完成功能出問題時可以刪除此文件。編譯工程后會自動生成。
========

vc調試技巧

http://blog.csdn.net/yaneng/article/details/5660889
VC調試技巧收集整理?
? ? ? 調試是一個程序員最基本的技能,其重要性甚至超過學習一門語言。不會調試的程序員就意味著他即使會一門語言,卻不能編制出任何好的軟件。
? ? ? 這里我簡要的根據自己的經驗列出調試中比較常用的技巧,希望對大家有用。本文約定,在選擇菜單時,通過/表示分級菜單,例如File/Open表示頂級菜單File的子菜單open。 ? ? ?  
? ? ?   
? ? ?   1 設置
? ? ?   為了調試一個程序,首先必須使程序中包含調試信息。一般情況下,一個從AppWizard創建的工程中包含的Debug?
? ? ? Configuration自動包含調試信息,但是是不是Debug版本并不是程序包含調試信息的決定因素,程序設計者可以在任意的Configuration中增加調試信息,包括Release版本。
? ? ?   為了增加調試信息,可以按照下述步驟進行:?
? ? ?   
? ? ?   a 打開Project settings對話框(可以通過快捷鍵ALT+F7打開,也可以通過IDE菜單Project/Settings打開)?
? ? ?   
? ? ?   b 選擇C/C++頁,Category中選擇general ,則出現一個Debug Info下拉列表框,可供選擇的調試信息方式包括:?
? ? ?    None:
? ? ?    沒有調試信息?
? ? ?    Line Numbers Only:
? ? ?    目標文件或者可執行文件中只包含全局和導出符號以及代碼行信息,不包含符號調試信息?
? ? ?    C7 Compatible:?
? ? ?    目標文件或者可執行文件中包含行號和所有符號調試信息,包括變量名及類型.函數及原型 等?
? ? ?    Program Database:?
? ? ?    創建一個程序庫(PDB),包括類型信息和符號調試信息。?
? ? ?    Program Database for Edit and Continue:?
? ? ?    除了上面的功能外,這個選項允許對代碼進行調試過程中的修改和繼續執行。
? ? ?    這個選項同時使#pragma設置的優化功能無效?
? ? ?   
? ? ?   c 選擇Link頁,選中復選框"Generate Debug Info",這個選項將使連接器把調試信息寫進可執行文件和DLL
? ? ? .如果C/C++頁中設置了Program Database以上的選項,則Link?
? ? ? incrementally可以選擇。選中這個選項,將使程序可以在上一次編譯的基礎上被編譯(即增量編譯),而不必每次都從頭開始編譯。?
?  
? ? ?   2 斷點
? ? ?   斷點是調試器設置的一個代碼位置。當程序運行到斷點時,程序中斷執行,回到調試器。斷點是?
? ? ? 最常用的技巧。調試時,只有設置了斷點并使程序回到調試器,才能對程序進行在線調試。
? ? ?   
? ? ?   設置斷點:可以通過下述方法設置一個斷點。首先把光標移動到需要設置斷點的代碼行上,然后?
? ? ?   按F9快捷鍵?
? ? ?   彈出Breakpoints對話框,方法是按快捷鍵CTRL+B或ALT+F9,或者通過菜單Edit/Breakpoints打開。打開后點擊Break?
? ? ? at編輯框的右側的箭頭,選擇 合適的位置信息。一般情況下,直接選擇line?
? ? ? xxx就足夠了,如果想設置不是當前位置的斷點,可以選擇Advanced,然后填寫函數、行號和可執行文件信息。
? ? ?   去掉斷點:把光標移動到給定斷點所在的行,再次按F9就可以取消斷點。同前面所述,打開Breakpoints對話框后,也可以按照界面提示去掉斷點。
? ? ?   
? ? ?   條件斷點:可以為斷點設置一個條件,這樣的斷點稱為條件斷點。對于新加的斷點,可以單擊Conditions按鈕,為斷點設置一個表達式。當這個表達式發生改變時,程序就?
? ? ? 被中斷。底下設置包括“觀察數組或者結構的元素個數”,似乎可以設置一個指針所指向的內存區的大小,但是我設置一個比較的值但是改動?
? ? ? 范圍之外的內存區似乎也導致斷點起效。最后一個設置可以讓程序先執行多少次然后才到達斷點。
? ? ?   
? ? ?   數據斷點:數據斷點只能在Breakpoints對話框中設置。選擇“Data”頁,就顯示了設置數據斷點的對話框。在編輯框中輸入一個表達式,當這個?
? ? ? 表達式的值發生變化時,數據斷點就到達。一般情況下,這個表達式應該由運算符和全局變量構成,例如:在編輯框中輸入?
? ? ? g_bFlag這個全局變量的名字,那么當程序中有g_bFlag= !g_bFlag時,程序就將停在這個語句處。
? ? ?   
? ? ?   消息斷點:VC也支持對Windows消息進行截獲。他有兩種方式進行截獲:窗口消息處理函數和特定消息中斷。在Breakpoints對話框中選擇Messages頁,就可以設置消息斷點。如果在上面那


個對話框中寫入消息處理函數的名字,那么?
? ? ? 每次消息被這個函數處理,斷點就到達(我覺得如果采用普通斷點在這個函數中截獲,效果應該一樣)。如果在底下的下拉?
? ? ? 列表框選擇一個消息,則每次這種消息到達,程序就中斷。
 
? ? ?   3 Watch
? ? ?   VC支持查看變量、表達式和內存的值。所有這些觀察都必須是在斷點中斷的情況下進行。
? ? ?   觀看變量的值最簡單,當斷點到達時,把光標移動到這個變量上,停留一會就可以看到變量的值。
? ? ?   VC提供一種被成為Watch的機制來觀看變量和表達式的值。在斷點狀態下,在變量上單擊右鍵,選擇Quick Watch,?
? ? ? 就彈出一個對話框,顯示這個變量的值。
? ? ?   單擊Debug工具條上的Watch按鈕,就出現一個Watch視圖(Watch1,Watch2,Watch3,Watch4),在該視圖中輸入變量或者表達式,就可以觀察?
? ? ? 變量或者表達式的值。注意:這個表達式不能有副作用,例如++運算符絕對禁止用于這個表達式中,因為這個運算符將修改變量的值,導致 軟件的邏輯被破壞。


? ? ?   4 Memory
? ? ?   由于指針指向的數組,Watch只能顯示第一個元素的值。為了顯示數組的后續內容,或者要顯示一片內存的內容,可以使用memory功能。在?
? ? ? Debug工具條上點memory按鈕,就彈出一個對話框,在其中輸入地址,就可以顯示該地址指向的內存的內容。
?   
? ? ?   5 Varibles
? ? ?   Debug工具條上的Varibles按鈕彈出一個框,顯示所有當前執行上下文中可見的變量的值。特別是當前指令涉及的變量,以紅色顯示。
 
? ? ?   6 寄存器
? ? ?   Debug工具條上的Reigsters按鈕彈出一個框,顯示當前的所有寄存器的值。
  
? ? ?   7 進程控制
? ? ?   VC允許被中斷的程序繼續運行、單步運行和運行到指定光標處,分別對應快捷鍵F5、F10/F11和CTRL+F10。各個快捷鍵功能如下:?
? ? ?   快捷鍵 說明?
? ? ?   F5 繼續運行?
? ? ?   F10 單步,如果涉及到子函數,不進入子函數內部?
? ? ?   F11 單步,如果涉及到子函數,進入子函數內部?
? ? ?   CTRL+F10 運行到當前光標處。?
? 
? ? ?   8 Call Stack
? ? ?   調用堆棧反映了當前斷點處函數是被那些函數按照什么順序調用的。單擊Debug工具條上的Call stack就顯示Call?
? ? ? Stack對話框。在CallStack對話框中顯示了一個調用系列,最上面的是當前函數,往下依次是調用函數的上級函數。單擊這些函數名可以跳到對應的函數中去。
 
? ? ?   9 其他調試手段
? ? ?   系統提供一系列特殊的函數或者宏來處理Debug版本相關的信息,如下:?
? ? ?   
? ? ?   10 宏名/函數名 說明?
? ? ?   TRACE 使用方法和printf完全一致,他在output框中輸出調試信息?
? ? ?   ASSERT 它接收一個表達式,如果這個表達式為TRUE,則無動作,否則中斷當前程序執行。對于系統中出現這個宏?
? ? ? 導致的中斷,應該認為你的函數調用未能滿足系統的調用此函數的前提條件。例如,對于一個還沒有創建的窗口調用SetWindowText等。?
? ? ?   VERIFY 和ASSERT功能類似,所不同的是,在Release版本中,ASSERT不計算輸入的表達式的值,而VERIFY計算表達式的值。?
? ? ?   
? ? ?   關注:
? ? ?   一個好的程序員不應該把所有的判斷交給編譯器和調試器,應該在程序中自己加以程序保護和錯誤定位,具體措施包括:?
? ? ?   
? ? ?    對于所有有返回值的函數,都應該檢查返回值,除非你確信這個函數調用絕對不會出錯,或者不關心它是否出錯。?
? ? ?    一些函數返回錯誤,需要用其他函數獲得錯誤的具體信息。例如accept返回INVALID_SOCKET表示accept失敗,為了查明?
? ? ? 具體的失敗原因,應該立刻用WSAGetLastError獲得錯誤碼,并針對性的解決問題。?
? ? ?    有些函數通過異常機制拋出錯誤,應該用TRY-CATCH語句來檢查錯誤?
? ? ?   程序員對于能處理的錯誤,應該自己在底層處理,對于不能處理的,應該報告給用戶讓他們決定怎么處理。如果程序出了異常,?
? ? ? 卻不對返回值和其他機制返回的錯誤信息進行判斷,只能是加大了找錯誤的難度。?
? ? ?    另外:VC中要編制程序不應該一開始就寫cpp/h文件,而應該首先創建一個合適的工程。因為只有這樣,VC才能選擇合適的編譯、連接?
? ? ? 選項。對于加入到工程中的cpp文件,應該檢查是否在第一行顯式的包含stdafx.h頭文件,這是Microsoft Visual?
? ? ? Studio為了加快編譯 速度而設置的預編譯頭文件。在這個#include?
? ? ? "stdafx.h"行前面的所有代碼將被忽略,所以其他頭文件應該在這一行后面被包含。
? ? ?    對于.c文件,由于不能包含stdafx.h,因此可以通過Project settings把它的預編譯頭設置為“不使用”,方法是:?
? ? ?   彈出Project settings對話框?
? ? ?   選擇C/C++?
? ? ?   Category選擇Precompilation Header?
? ? ?   選擇不使用預編譯頭。
? ? ? [url]http://www.yzcc.com/yzcc/vv/08475592434.html[/url]


? ? ? 其他技巧:


? ? ? 1.在調試狀態下怎樣查看錯誤消息(GetLastError())?
? ? ? 通常可以用GetLastError()得到錯誤編號然后用FormatMessage(...)得到錯誤描述。
? ? ? 這里有一個更直接的辦法:在Watch窗口添加@err,hr


? ? ? 2.怎樣知道程序是否有內存泄漏(Memory Leak)?
? ? ? 在VC開發環境下Press?
? ? ? [F5],在調試狀態下運行程序,測試有可能出現內存泄漏的操作,關閉程序,在Output窗口查看運行信息.如果出現泄漏,在Output中會有記錄。當然,不能完全依靠這種方式來發現程序運行有內存泄漏。


? ? ? 3.當某一變量滿足某種條件時,停止在斷點.
? ? ? 如以下一程序片段:
? ? ? 2 int iLocation;
? ? ? ...
? ? ? 30 iLocation++
? ? ? ...
? ? ? 要求: 在line30設有斷點,并想在iLocation>100?
? ? ? 本文來源:[url]http://blog.tianya.cn/blogger/post_show.asp?BlogID=237133&PostID=3587659[/url]


   便于調試的代碼風格:


不用全局變量
所有變量都要初始化,成員變量在構造函數中初始化
盡量使用const
詳盡的注釋


VC++編譯選項:


總是使用/W4警告級別
在調試版本里總是使用/GZ編譯選項,用來發現在Release版本中才有的錯誤
沒有警告的編譯:保證在編譯后沒有任何警告,但是在消除警告前要進行仔細檢查


調試方法:


1、使用 Assert(原則:盡量簡單)
assert只在debug下生效,release下不會被編譯。


例子:
char* strcpy(char* dest,char* source)
{
assert(source!=0);
assert(dest!=0);
char* returnstring = dest;
while((*dest++ = *source++)!= ‘/0’)
{
;
}
return returnstring;
}?
2、防御性的編程


例子:
char* strcpy(char* dest,char* source)
{
if(source == 0)
{
assert(false);
reutrn 0;
}
if(dest == 0)
{
assert(false);
return 0;
}
char* returnstring = dest;
while((*dest++ = *source++)!= ‘/0’)
{
;
}
return returnstring;
}?
3、使用Trace


以下的例子只能在debug中顯示,


例子:


a)、TRACECString csTest = “test”;
TRACE(“CString is %s/n”,csTest);
b)、ATLTRACE


c)、afxDump
CTime time = CTime::GetCurrentTime();
#ifdef _DEBUG
afxDump << time << “/n”;
#endif
4、用GetLastError來檢測返回值,通過得到錯誤代碼來分析錯誤原因


5、把錯誤信息記錄到文件中


異常處理


程序設計時一定要考慮到異常如何處理,當錯誤發生后,不應簡單的報告錯誤并退出程序,應當盡可能的想辦法恢復到出錯前的狀態或者讓程序從頭開始運行,并且對于某些錯誤,應該能夠容錯,即允


許錯誤的存在,但是程序還是能夠正常完成任務。


調試技巧


1、VC++中F5進行調試運行


a)、在output Debug窗口中可以看到用TRACE打印的信息
b)、 Call Stack窗口中能看到程序的調用堆棧


2、當Debug版本運行時發生崩潰,選擇retry進行調試,通過看Call Stack分析出錯的位置及原因
3、使用映射文件調試


a)、創建映射文件:Project settings中link項,選中Generate mapfile,輸出程序代碼地址:/MAPINFO:?
LINES,得到引出序號:/MAPINFO: EXPORTS。
b)、程序發布時,應該把所有模塊的映射文件都存檔。
c)、查看映射文件:見” 通過崩潰地址找出源代碼的出錯行”文件。


4、可以調試的Release版本


Project settings中C++項的Debug Info選擇為Program Database,Link項的Debug中選擇Debug?
Info和Microsoft format。


5、查看API的錯誤碼,在watch窗口輸入@err可以查看或者@err,hr,其中”,hr”表示錯誤碼的說明。
6、Set Next Statement:該功能可以直接跳轉到指定的代碼行執行,一般用來測試異常處理的代碼。
7、調試內存變量的變化:當內存發生變化時停下來。


常見錯誤


1、在函數返回的時候程序崩潰的原因


a)、寫自動變量越界
b)、函數原型不匹配


2、MFC


a)、使用錯誤的函數原型處理用戶定義消息


正確的函數原型為:
afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);
3、謹慎使用TerminateThread:使用TerminateThread會造成資源泄漏,不到萬不得已,不要使用。


4、使用_beginthreadex,不要使用Create Thread來常見線程。


WindowS 調試


1.Windows跟蹤語句:


(1)TRACE(_T(“Warning (FunctionName):Object %s not found./n”),objectName);


在輸出的調試窗口會輸出結果。跟蹤信息輸出到輸出窗口output window中。[調試版本中使用]


(2)C++的C運行時刻庫函數跟蹤語句
? ? ANSI C 運行時刻庫函數沒有跟蹤語句,但是VC++的C運行時刻庫函數有。可使用_RPTn或_RPTFn調試報告宏,但是你必須在程序中引用crtdbg.h,并利用C運行時刻函數庫鏈接:
? ?_RPT0(reportType,format);
? ?_RPT1(reportType,format,arg1);
? ?_RPT2(reportType,format,arg1,arg2);


? ?_RPTF0(reportType,format);
? ?_RPTF1(reportType,format,arg1);
? ?_RPTF2(reportType,format,arg1,arg2);
? ?例子:
? ? ? ? ? int a =1000,b=2000;
? ? ? ? ?int *p =&a;
? ? ? ? ?int *q = &b;
? ? ? ?_RPTF2(_CRT_WARN,"%x ,%x",p,q); //直接在outputwindow中輸出
? ? ? ?_RPTF2(_CRT_ERROR,"%x ,%x",p,q); ? //彈出ERROR對話框
? ? ? ?_RPTF2( _CRT_ASSERT,"%x ,%x",p,q); ? //彈出AEESRT對話框
reportType:_CRT_WARN _CRT_ERROR _CRT_ASSERT
其中_CRT_WARN用于跟蹤語句,_RPTFn宏報告了源碼文件名和調用這些宏的行號。[調試版本中使用]
可以使用_CrtSetReportMode函數改變默認輸出設置,(比如輸出到調試器輸出窗口,文件,消息框中),_CrtSetReportFile可以指定將報告輸出到哪個文件中。


(3)MFC中的跟蹤語句
? ? ? ?區別:使用TRACE宏時,需要使用_T宏來格式化參數以正確解決Unicode的校正,反之,在TRACEn類型的宏中,不必使用_T宏。
? ? ? ?TRACE(_T("ssss/n"));
? ? ? ?TRACE2("%d r %d l/n",1,2);


(4)異常和返回值


C++程序中可以使用異常和返回值來返回狀態信息。C語言返回一個函數的狀態的最好方法就是它的返回值
Try
{
//code may fail
}
Catch
{
//handle the failure
}
只有在拋出異常的時候會有開銷!Catch塊有一些開銷,但是try塊有很少的開銷!只能在調試版中處理異常,并彈出MessageBox,發布版不處理異常,為的就是優化。
? ? ?try
? ? ?{
? ? ? ?int *pInt = 0;
? ? ? ?*pInt =42;
? ? ?}
? ? ?catch(...)
? ? ?{
? ? ? ?MessageBox(_T("Exception was caught!"),_T("Exception test"),MB_OK); ??
? ? ?}
? ? ? (5)ANSI C++ 運行時刻函數庫跟蹤
具體有:C語言的stderr和C++語言的clog流,在Windows程序中沒有任何效果!


(6)OutputDebugString (_T(“trace ? debug info!/n”));[調試版本中使用]
? ? ? ?如果只想在調試版本中使用OutputDebugString,可以使用下面得宏來實現:
#ifdef ? _DEBUG
#define OutputTraceString(text) ? OutputDebugString(text)
#else
#define OutputTraceString(text) ? ((void) (0))
#endif


使用AfxOutputDebugString
AfxOutputDebugString宏使用和OutputDebugString一樣的語法。


7.使用CObiect::Dump
CObject類有一個轉儲(dump)虛擬函數,繼承于它的所有子類函數都可以重載這個函數,輸出它們的值。
例 1 -2:用下列語句輸出CObject派生類pObject的值。afxDump是預定義的全局變量CDumpContext,注意 CDumpContext對最一般的內建數據類型及CObject的指針和引用支持插入操作符(<<)


。有幾個CObject派生的類也有定 義的插入操作符,CPoint,CSize,CRect,CString,CTime和CTimeSpan。
#if _DEBUG
AfxDump(pObiect);
pObject->Dump(afxDump);
afxDump<<pObject;
#endif


例1-3:
afxDump<<_T(“Warning:This object doesn’t seem right:/n”)<<pObject;
8.使用AfxDump
AfxDump是MFC中相當于cerr流的跟蹤語句,所以你可以直接向它輸出跟蹤消息。
TRACE宏由afxDump實現,afxDump由AfxOutputDebugString實現。而AfxOutputDebugString在調試版中由_RPT0宏實現。可以使用下面的方法將afxDump重定向。
#ifdef _DEBUG
CFile dumpFile; //必須為全局變量
? ? ?dumpFile.Open(_T("dump.log"),CFile::modeWrite|CFile::modeCreate);
? ? ?afxDump.m_pFile = &dumpFile;
#endif
9.使用AfxDumpStack
可以使用AfxDumpStack函數輸出一個調用棧:
void AFXAPI AfxDumpStack(DWORD dwTarget = AFX_STACK_DUMP_TARGET_DEFAULT);
參 數:dwTarget決定在調試和發布版本中輸出到什么地方,可以輸出到TRACE宏,OutputDebugString或到剪貼板。如果使用 AFX_STACK_DUMP_TARGET_TRACE,含義是在調試版中輸出到


TRACE宏,而在發布版本中沒有輸出!如果你希望在發布版本中輸出, 可使用AFX_STACK_DUMP_TARGET_ODS選項,而且必須在路徑中有Imagehlp.dll文件。在project&?


#61664;settings&#61664;Link&#61664;Category&#61664;Debug Both formats。?
10.ATL跟蹤語句 最基本的類型是AtlTrace函數:
inline void_cdecl AtlTrace(LPCTSTR format……);
ATLTRACE (format……);


和MFC TRACE宏一樣,它使用一個512字節固定大小的緩沖區,如果它的參數需要一個大于512字節的文本緩沖區,會導致一個出錯的斷言。實際上,它是使用API函數OutputDebugString實現的,


因此它的輸出不能改變到其他目標。
ATL跟蹤語句的另一個選擇AtlTrace2函數:
Inline void _cedecl AtlTrace2(DWORD category,UINT level,LPCTSTR format,…);
ATLTRACE(category,level,format);
該 函數增加了一個參數跟蹤類別(category)(例如,atlTraceCOM,atlTraceWindowing和 atlTraceControl)和一個參數嚴格級別。類別值是位掩碼,ATL自身使用介于0-2的級別值,0級指最嚴格的級別


。 和AtlTrace函數類似,AtlTrace2函數只能用在調試版本中!
11.VC++消息Pragma
Pagama是一個編譯時的跟蹤語句,可用來警告在預處理過程中發現的潛在的編連(build)問題
12.處理長字符串:[例如處理SQL語句]
(1)MFC下[只能調試版]
TRACE(longString); //assert if _tcslen(longString)>511,最大是512
#ifdef _DEBUG
afxDump<<longString;//dosen’t assert for long strings 不需要判斷
#endif
(2)ATL下[只能調試版]
ATLTRACE(longString); //assert if _tcslen(longString)>511,最大是512
#ifdef _DEBUG
OutputDebugString(longString); //dosen’t assert for long strings 不需要判斷
#endif
13.處理大量的跟蹤輸出。
如果跟蹤消息數據產生的速度超過輸出窗口處理的速度,那么消息會塞滿緩沖區,數據會丟失。
簡單方法:在輸出大量數據的代碼段,例如對象轉儲函數時候,調用 Sleep API函數。例如:Sleep(100).


?調試
1.當錯誤發生得時候,調用GetLastError()得到相應得錯誤碼
錯誤碼得位域有固定的格式,,在C:/Program Files/Microsoft Visual Studio/VC98/Include/Winerror.h中有詳細的說明:
//
// ? Values are 32 bit values layed out as follows:
//
// ? 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// ? 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// ? +---+-+-+-----------------------+-------------------------------+
// ? |Sev|C|R| ? ? Facility ? ? ? ? ? | ? ? ? ? ? ? ? Code ? ? ? ? ? ? |
// ? +---+-+-+-----------------------+-------------------------------+
//
// ? ? ? Sev - is the severity code ? ? ? 安全代碼
//
// ? ? ? ? ? 00 – Success ? ? ? ? ? 0-安全 ??
// ? ? ? ? ? 01 – Informational ? ? 1-信息
// ? ? ? ? ? 10 – Warning ? ? ? ? 2-警告
// ? ? ? ? ? 11 – Error ? ? ? ? ? ? 3-錯誤
// ? ? ? C - is the Customer code flag?
客戶代碼:0-Microsoft定義的,1-客戶定義的
// ? ? ? R - is a reserved bit 保留位必須是0 ?
// ? ? ? Facility - is the facility code工具-Microsoft 定義的
// ? ? ? Code - is the facility's status code 工具狀態代碼-Microsoft或客戶定義
? ?工具:更好的查看錯誤代碼的方法,Tools-》Error Lookup;在VC++調試器的watch窗口中輸入@ERR監視GetLastError的返回數值,ERR是調試器用來顯示最新錯誤碼的一個虛擬寄 存器。還可


以用 @ERR,hr將錯誤碼轉換為文本格式
? ?
? ?技巧:在調試中,按F11鍵,Alt+8顯示反匯編窗口,在Edit菜單中選擇Go To命令,在GoTo對話框的Go to what中選擇Address選項,在Enter address expression中輸入導致崩潰的地址。


創 建映射文件的方法:Project&#61664;Settings&#61664;Link&#61664;Generate mapfile.即可在工程的Debug文件下看到。映射文件里面所有的公共符號都使用混合名字。可使用VC++的名字


解析工具(Undname)將混合 名字轉換到原始名字。你可以在“開始”&#61664;”運行”&#61664;”cmd”&#61664;輸入
C:/Documents and Settings/zhangzhongping>cd C:/Program Files/Microsoft Visual Studio/Common/Tools
輸入:
C:/ProgramFiles/MicrosoftVisualStudio/Common/Tools>Undname ?RandException@@YGXHHHH@Z
Microsoft(R) Windows NT(R) Operating System
UNDNAME Version 5.00.1768.1Copyright (C) Microsoft Corp. 1981-1998
輸出:
>> ?RandException@@YGXHHHH@Z == RandException


當輸入-f時,顯示整個函數的原型!查看映射文件的時候,若出現重載函數,名字解析工具很有用!
輸入:
C:/ProgramFiles/MicrosoftVisualStudio/Common/Tools>Undname-f ?RandException@@YGXHHHH@Z
Microsoft(R) Windows NT(R) Operating System
UNDNAME Version 5.00.1768.1Copyright (C) Microsoft Corp. 1981-1998
輸出:
>> ?RandException@@YGXHHHH@Z == void __stdcall RandException(int,int,int,int)


使用MFC和ATL的DEF文件:


MFC的DEF文件在
C:/ProgramFiles/MicrosoftVisual Studio/VC98/MFC/SRC/Intel目錄下。
ATL的DEF文件在
C:/Program Files/Microsoft Visual Studio/VC98/ATL/SRC目錄下。
如 果用戶運行自己的程序出現:The ordinal 6880 could not be located in the dynamic link Library MFC42.dll信息。你可查看MFC42.DEF中對應的6880號函數:??


ScreenToClient@CWnd@@QBEXPAUtagRECT@@@Z @ 6880 NONAME.然后可以用名字解析工具解析混合名字如下:
輸入:
C:/Program Files/Microsoft Visual Studio/Common/Tools>Undname -f ?ScreenToClient@CWnd@@QBEXPAUtagRECT@@@Z @ 6880 NONAME
Microsoft(R) Windows NT(R) Operating System
UNDNAME Version 5.00.1768.1Copyright (C) Microsoft Corp. 1981-1998
輸出:
>> ?ScreenToClient@CWnd@@QBEXPAUtagRECT@@@Z == public: void __thiscall CWnd::ScreenToClient(struct tagRECT *)const
>> @ == @
>> 6880 == 6880
>> NONAME == NONAME
使用依賴關系瀏覽工具:
VC++依賴關系瀏覽工具(COMMON/TOOLS/Depends.exe)


?內存泄漏的調試
在VC中我們使用_CrtDumpMemoryLeaks()來檢測內存泄漏。
例子:
void CTRACEDlg::OnButton1()?
{
? ? ?int *pLeak = new int; //故意造成內存泄漏
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
? ? ?//delete pLeak;
? ? ?//pLeak = NULL;
? ? ?_CrtDumpMemoryLeaks();//調用此函數在output window的Debug窗口中顯示內存泄漏的地址的數據。
? ??
}
Debug窗口中顯示:
Detected memory leaks!
Dumping objects ->
C:/ProgramFiles/MicrosoftVisualStudio/MyProjects/TRACE/TRACEDlg.cpp(181) : {89} normal block at 0x004213B0, 4 bytes long.
Data: < ? ? > CD CD CD CD?
Object dump complete.




注意:0xCD表示已經分配的數據
? ? ? ?0xDD表示已經釋放的數據
? ? ? ?0xFD表示被保護的數據


斷言
1.斷言的特征:
(1)發現運行時刻錯誤(用戶輸入錯誤,資源分配錯誤,文件系統錯誤,硬件錯誤或其他類型錯誤)
(2)斷言中的布爾表達式顯示的是某個對象或者狀態的有效性,而不是正確性
(3)斷言在條件編譯后只存在調試版本里面,特別是,斷言只在_DEBUG符號定義后,才能編譯!
(4)斷言不能包含程序代碼,也不能有副作用,不能修改程序變量,也比能調用修改程序變量的函數
(5)斷言只是給程序員提供有用信息的
2.斷言的類型
(1)ANSI C斷言
Void assert(expression) ? ? 包含在assert.h頭文件中(最好不用assert)
原因:*當文件名太長的化,對話框顯示的路徑將會被截至掉!
*函數是由ANSI NDEBUG函數驅動的,如果定義了NDEBUG后,斷言就被取消!


如果要啟用JIT調試(Just-in-time),在Tools&#61664;Options&#61664;Debug
中選擇Just-in-time debugging,默認也會勾選上OLE RPC debugging
單擊“重試(R)”就會顯示出錯誤所在的標記行。


(2)C運行時刻函數庫斷言
_ASSERT(Boolean Expression) ? (crtdbg.h)[不用]


_ASSERTE(Boolean Expression) ? (crtdbg.h)[經常用這個]


_ASSERTE宏更能給出更多簡潔,有用的信息,顯示了斷言!


(3)MFC庫中的斷言


ASSERT(Boolean expression) ASSERT宏和_ASSERT宏顯示的消息框相同。VERIFY(Boolean expression) VERIFY 中的BOOL表達式在發布版本中被保留了下來。它簡化了對返回值的判斷!


CString str;


VERIFY(str.LoadString(IDS_STRING));//不要用VERIFY宏


ASSERT_VALID宏,被用來決定一個指向CObject派生類的對象的指針是否有效。ASSERT(pObjectDerivedFromCObject);主要是在使用CObject派生類對象之前調用,檢查對象的有效性。


ASSERT_KINDOF(className,pObjectDerivedFromCObject);


ASSERT_POINTER(pointer,pointerType);


ASSERT_NULL_OR_POINTER(pointer,pointerType);


AfxlsValidAddress(const void*memoryAddress,UINT memoryBytes,BOOL isWriteable = TRUE);


BOOL AfxlsValidString (LPCSTR string, int stringLength = -1);


(4)ATL斷言


如果你使用ATL,crtdbg.h就包含在atlbase.h中。在任何ATL代碼中,ATLASSERT才是你的選擇,在atldef.h中你會發現ATLASSERT是_ASSERT的一個別名。


優點:在ATL程序中使用ATLASSERT可以讓你使用自己的斷言。


(5)考慮使用_ASSERTE(FALSE)來簡化防御性的編程和斷言的結合,要想得到描述性的斷言消息,考慮使用_ASSERTE(“Problem description.”==0).


_ASSERTE("This is the object requires the MM_TEXT mapping mode" == 0);


If (!expression)
{


//handle error


_ASSERT(FALSE);



}


If(FAILED(SomeFunction()))
{
//handle error


_ASSERT(FALSE)
}


(6)考慮使用_CrtSetReportMode和_CrtSetReportFile


========

總結

以上是生活随笔為你收集整理的VC++调试技巧学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。