Visual Studio調(diào)試C/C++教程指南
1. 前言
Visual Studio(VS)是微軟開發(fā)的一款集成開發(fā)環(huán)境(IDE)軟件,支持C/C++、C#、VB、Python等開發(fā)語言,開發(fā)桌面、Web等應用程序。VS功能極其強大,使用極其便利,用戶數(shù)量最多,被譽為"宇宙第一IDE"。
熟悉地掌握基于VS的C/C++調(diào)試技術(shù),可以大幅提升調(diào)試性能。隨著VS版本的更新,其功能越來越強大,本文的內(nèi)容是基于VS2019進行驗證測試的,之前版本VS可能有少量特性不支持。
2. 基礎
2.1. 調(diào)試
代碼調(diào)試主要指使用調(diào)試工具來檢查和修復代碼中的錯誤和問題。代碼調(diào)試主要有運行調(diào)試、打印調(diào)試、內(nèi)存分析、靜態(tài)分析、性能分析等。
2.2. 符號文件
符號文件(Symbol File)是指在編譯程序時生成的包含調(diào)試信息的文件。它們通常與可執(zhí)行文件或動態(tài)鏈接庫(DLL)配對存在,用于提供程序的調(diào)試信息。VC生成的符號文件為PDB(Program Database)文件。其中存儲變量名、函數(shù)名、代碼行號、類型信息和棧信息等。exe/dll與pdb文件是一一對應的。每次重新編譯代碼,都會生成新的pdb。
2.3. 調(diào)試器
Microsoft Visual C/C++的調(diào)試器名稱叫做"Visual Studio Debugger"。在調(diào)試exe時,其會讀取exe文件中記錄的PDB路徑信息(這個路徑是開發(fā)電腦編譯時生成的PDB路徑),如果這個PDB路徑不存在,那么調(diào)試器會在exe目錄去找PDB,如果依然找不到PDB,則啟用無PDB調(diào)試。無PDB調(diào)試只能查看匯編信息和寄存器信息。
調(diào)試方式
3. 本地調(diào)試
VS工程默認即為本地調(diào)試(Local Windows Debugger)。選定啟動工程,按F5或通過菜單Debug->Start Debugging。
命令行參數(shù)(Command Arguments),給exe配置命令行參數(shù)。
附加(Attach),默認No。Yes表示附加當前路徑的進程進行調(diào)試。

3.1. 遠程調(diào)試
將開發(fā)電腦上的Remote Debugger目錄拷貝到生產(chǎn)電腦。

根據(jù)程序的類型x64/x86打開相應的目錄,并打開生產(chǎn)電腦目錄下的msvsmon.exe。
首次調(diào)用時,會彈出遠程調(diào)試配置窗口,勾選所有的允許遠程調(diào)試器與這些網(wǎng)絡通信。
配置msvsmon.exe的Tools->Options。4015是默認的端口號,一般不建議修改。

- 獲取生產(chǎn)電腦的IP,局域網(wǎng)網(wǎng)絡通信,可以使用計算機名:端口號的方式,也可以使用IP:端口號的方法。但是在訪問跨網(wǎng)關的局域網(wǎng)電腦時,計算機名可能無法解析出對應的IP地址,導致訪問失敗,所以更推薦IP:端口號的訪問方式。
- 依據(jù)下圖配置相關信息。

按F5啟動調(diào)試,調(diào)試遠程exe和調(diào)試本地exe后續(xù)操作完全一致。
3.2. 附加調(diào)試
打開exe。
從菜單啟動Debug->Attach to Process,選擇需要調(diào)試的進程進行附加。如果是遠程進程,配置下圖信息。

3.3. 外網(wǎng)調(diào)試
遠程調(diào)試一般是針對局域網(wǎng)進行調(diào)試。但是有些時候,問題進程在外地,出差不方便或成本太高,非常需要一種能夠穿透廣域網(wǎng)進行調(diào)試的方法。最簡單的方法是使用VPN將目標電腦遠程連接到開發(fā)電腦,這樣目標電腦和開發(fā)電腦就相當于處在同一個局域網(wǎng),就可以使用普通的遠程調(diào)試來進行外網(wǎng)目標電腦調(diào)試。
3.4. DLL調(diào)試
在DLL工程的屬性中Debugging的Command中選擇要執(zhí)行的exe,然后在dll中設置相關斷點。再按F5調(diào)試,即會中斷在DLL工程的斷點處。

4. 斷點調(diào)試
int 3是x86-64架構(gòu)CPU上的中斷指令,用于在程序執(zhí)行過程中觸發(fā)軟件中斷。VS在給代碼添加斷點時,就是將指定行對應的代碼修改為int 3指令,并且調(diào)試器接管代碼。繼續(xù)單步執(zhí)行時,會還原int 3覆蓋的代碼。
4.1. 斷點類型
4.1.1. 普通斷點
在代碼指定行按F9或右鍵菜單Breakpoint->Insert Breakpoint設置普通斷點。
4.1.2. 條件斷點
在斷點上右鍵選擇Conditions。

設置 i == 5, 然后點擊Close。按F5執(zhí)行,代碼會停止在斷點處,此時i==5。

指定當前斷點觸發(fā)指定次數(shù)時中斷下來。

當前斷點運行在指定線程時才中斷下來。

4.1.3. 行為斷點
行為斷點(Actions Breakpoint),也稱Tracepoint,因為斷點觸發(fā)時會在Output窗口打印信息。Continue Code Execution勾選表示不停止在斷點處,如果選空表示停止在斷點處。

Output窗口顯示:The value of z is 0x0000001e. 0x2C74
$PID,是偽指令??捎玫膫沃噶钊缦拢?/p>

4.1.4. 數(shù)據(jù)斷點
數(shù)據(jù)斷點(Data Breakpoint),當然變量地址的內(nèi)容發(fā)生改變時,即中斷下來。如下圖,Address編輯框可以直接填寫變量的地址,也可以使用取地址符來獲取變量的地址。數(shù)據(jù)斷點只能針對有效數(shù)據(jù)設置斷點,并且只能在已經(jīng)開始調(diào)試之后,在Breakpoint窗口的菜單New->Data Breakpoint來設置。

4.1.5. 系統(tǒng)函數(shù)斷點
例如想在CreateFile函數(shù)中下斷點。可以使用dhb.exe在相應的
dbh.exe -s:srv*C:\Symbols*Symbol information -d C:\Windows\SysWOW64\kernel32.dll enum *CreateFile*

然后Breakpoints->New->Function Breakpoint:

運行就會斷在系統(tǒng)API函數(shù)處,通過調(diào)用棧查找到調(diào)用的函數(shù)。

4.1.6. 軟件斷點
除了通過VS來添加斷點外,我們也可以在代碼中主動添加軟件斷點__debugbreak()/DebugBreak函數(shù),或是斷言ASSERT(0)。
__debugbreak()/DebugBreak是代碼到此處立即中斷,而斷言則是根據(jù)參數(shù)邏輯值來決定是否中斷。軟件斷點主要用來在代碼潛在的異常出現(xiàn)時產(chǎn)生中斷提示開發(fā)者。
4.2. 調(diào)試行為
4.2.1. 基本行為
工具欄或Debug菜單或鼠標右鍵都有調(diào)試行為的選項。

Break All,中斷當前所有正在執(zhí)行的代碼。當代碼進入死循環(huán)時,點擊Break All,代碼即會中斷下來,此時遍歷線程查看函數(shù)調(diào)用棧,即能發(fā)現(xiàn)死循環(huán)代碼位置。
Stop Debugging,停止當前調(diào)試。
Restart,重新開始調(diào)試。
Show Next Statement,光標跳到下一次要執(zhí)行的代碼處。
Step Into,快捷鍵F11,進入當前語句所調(diào)用的函數(shù)內(nèi)部,并停在函數(shù)的第一行。如果當前行沒有函數(shù)調(diào)用,則直接運行至下一行。
Step Over,快捷鍵F10,執(zhí)行當前語句,但不進入函數(shù)內(nèi)部。
Step Out, 快捷鍵Shift+F11,執(zhí)行完當前函數(shù),暫停在函數(shù)調(diào)用處。
Step Backward,即退回到上一次代碼暫停的位置,恢復上次調(diào)試的信息。Step Forward,前行到退回前的代碼暫停的位置。這是基于棧快照進行的調(diào)試,VS會在幾次中斷時,保存對應棧信息,尤其是當我們想反復調(diào)試一個算法時,使用Step Backward會非常方便。
4.2.2. 高級行為
Run To Cursor,運行到光標處中斷,可以通過鼠標右鍵來執(zhí)行,也可在光標處的代碼行的圖標上點擊。

Force Run To Cursor,強制運行到光標處,會跳過中間設置的斷點。
自定義,鼠標放在箭頭上,可以將下一個可執(zhí)行代碼的位置拖動到任意位置。拖動需要依賴先前的代碼,否則可能產(chǎn)生異常。

5. 調(diào)試窗口
5.1. Output
Output Debug窗口主要輸出調(diào)試過程的信息,主要包括:
Exception Messages
Step Filtering Messages
Module Load Messages
Module Unload Messages
Process Exit Messages
Thread Exit Messages
Program Qutput
其中Program Output是代碼運行時輸出的信息,主要通過Trace函數(shù)或OutputDebugString函數(shù)來將信息輸出到Output窗口。如果是非調(diào)試狀態(tài)下,OutputDebugString的輸出信息則需要DbgView工具來接收并顯示。

5.2. Locals
Locals窗口顯示調(diào)試時當前執(zhí)行代碼所在函數(shù)所在的棧的局部變量的值和類型。

5.3. Autos
Autos窗口顯示調(diào)試時當前執(zhí)行代碼所在函數(shù)所在的棧的上下文棧變量值和類型。

5.4. Watch
Watch窗口總共有4個,可以在菜單Debug->Windows->Wartch中選擇。Watch窗口可以顯示當前棧內(nèi)存的局部變量,全局變量等,支持16進制形式顯示,并支持實時修改變量值。
支持簡單的表達式顯示,如x+y, sizeof(x)等。
支持格式化顯示,如(int*)(szBuff),4將Buff轉(zhuǎn)換為int*,再格式化為4個元素顯示。

Watch窗口還支持顯示偽變量,如:
$tid – 當前線程的的線程 ID
$pid – 進程 ID
$cmdline – 附加進程的命令行字符串
$user – 運行在程序中的賬戶信息
$registername – 顯示指定寄存器的寄存器內(nèi)容
$err – 顯示最近錯誤的錯誤碼
$err, hr – 顯示最近錯誤的消息
5.5. Memory
Memory窗口是用來顯示地址對應的內(nèi)容,Memory窗口有4個從菜單Debug->Windows->Memory中選擇。
Adress編輯框填寫變量地址,Columns選擇每行顯示的內(nèi)容數(shù)量。

5.6. QuickWatch
QuickWatch窗口是快捷觀察、修改變量的窗口。

5.7. Disassembly
參數(shù)傳遞、函數(shù)返回等一些復雜的語法形式,要想理解其深層執(zhí)行邏輯,就需要單步執(zhí)行匯編代碼來觀察其隱藏邏輯細節(jié)。

5.8. Registers
寄存器窗口,顯示當線程的寄存器信息。

5.9. Call Stack
函數(shù)調(diào)用棧窗口,顯示當前線程的函數(shù)棧調(diào)用情況??梢酝ㄟ^Threads窗口選定當前線程。

5.10. Immediate Window
Debug->Windows->Immediate窗口。立即窗口主要用來查看、修改變量,執(zhí)行函數(shù),表達式等。

6. 多線程
6.1. Threads
Threads是顯示當前進程的所有運行的線程信息的窗口。雙擊線程所在行,即將當前代碼窗口、調(diào)用棧窗口等相關窗口的內(nèi)容更新為選定線程。
當進程有多個工作者線程時,且只想調(diào)試其中一個線程時,可以將不關心的線程使用Freeze冰凍起來。冰凍的線程在按F5運行時,依然冰凍著不運行。使用Thaw解凍線程,線程將恢復為正??梢哉{(diào)試的狀態(tài)。

6.2. 條件斷點
在多線程中,根據(jù)線程信息來設置相應的斷點來觀察期望的變量信息。

6.3. Parallel Watch
Debug->Window->Parallel Watch可以顯示幾個線程同時調(diào)用的函數(shù)變量的情況,更方便地調(diào)試多線程。

6.4. 線程結(jié)構(gòu)圖
打開Debug->Windows->Parallel Stack窗口,會顯示所有線程的棧,并顯示當前線程棧。相比Threads窗口更直觀。

7. 參數(shù)配置
7.1. 增量鏈接
增量鏈接在Debug下默認打開,在Release下默認關閉。通過Linker->General->Enable Incremental Linking來開啟和關閉。增量鏈接還需要配置C/C++->General->Debug Information Format->Program Database for Edit And Continue (/ZI)。
增量鏈接的用處是在斷點單步調(diào)試代碼的時候,編輯代碼,然后繼續(xù)單步執(zhí)行時,VS會自動增量鏈接,不用重新編譯源代碼,然后繼續(xù)單步執(zhí)行代碼進行調(diào)試。
增量鏈接是調(diào)試時使用,增量編譯則是編譯時只編譯修改的源文件,兩者不相同。
7.2. 優(yōu)化級別
Debug版本下,默認關閉代碼優(yōu)化,此時代碼的調(diào)試信息與代碼源文件是一一對應,調(diào)試更方便。Release版本下,默認使用O2優(yōu)化,此時代碼優(yōu)化程度非常大,調(diào)試信息與代碼源文件無法一一對應。如果想調(diào)試Release版本,則需要關閉優(yōu)化。
7.3 宏展開
一些復雜的宏,非常難以調(diào)試。如何查看宏預處理之后展開形成的代碼呢?C/C++->Preporcessor->Preprocess to a File配置默認是關閉的,打開此配置為Yes(/P)表示將生成預處理后的文件,文件與源文件同名,后綴為.i。在.i文件中可以查看所有宏展開的結(jié)果,以及其他預處理的結(jié)果。
7.4. 顯示鏈接細節(jié)
VS 鏈接器默認只顯示一些關鍵的鏈接信息。可以通過Linker->General->Show Progress配置Display all progress messages(/VERBOSE)來顯示詳細的鏈接信息,可以更方便地分析一些鏈接異常的錯誤。
7.5. 警告
7.5.1. 編譯警告
為了提升代碼的可靠性,警告也需要認真對等。
C/C++->All Options->Warning Level,選擇合適的警告級別,初期可以選擇W3級別。
C/C++->All Options->Treat Warning As Errors,初期可以不設置。
C/C++->All Options->Treat Specific Warnings As Errors,可以將一些關鍵警告設置為錯誤。

7.5.2. 鏈接警告
Linker->All Options->Treat Linker Warning As Errors,根據(jù)需要將警告作為錯誤對待。
Dump調(diào)試
8.概念
Dump文件(Dump File),也叫轉(zhuǎn)儲文件,以.DMP為文件后綴。dump文件是進程在內(nèi)存中的鏡像文件,通過轉(zhuǎn)換然后存儲成以.DMP后綴的文件。dump文件根據(jù)存儲時的選項不同,會生成不同大小的文件,其中記錄信息也自然有所不同。
8.1. 轉(zhuǎn)儲文件生成
通過Windows進程管理器,選擇指定的進程,右鍵生成轉(zhuǎn)儲文件。
通過函數(shù)MiniDumpWriteDump生成轉(zhuǎn)儲文件。
8.2. 調(diào)試轉(zhuǎn)儲文件
選擇與生成Dump文件相同版本的VS。
啟動VS并打開Dump文件。
必須保證生成Dump文件的程序的PDB文件和源代碼相一致。
VS2005打開Dump文件時,直接按F5調(diào)試,代碼會停在出錯的地方,通過Call Stack窗口查看。
VS2010打開Dump文件時,

需要通過Set symbol paths設置符號文件路徑,也即PDB文件路徑。然后點擊Debug with Native Only,代碼即會中斷在出錯的地方,通過Call Stack窗口查看相關信息。
變量溢出
變量內(nèi)存溢出分為上溢(Overflow)和下溢(Underflow)。內(nèi)存溢出導致的異常是C++代碼最為難以調(diào)試的Bug之一,因為內(nèi)存溢出導致的異常往往不會立即出現(xiàn),而是展現(xiàn)在后面的函數(shù)中。因為內(nèi)存溢出可能覆蓋了后面的代碼,導致后面的代碼執(zhí)行異常。
AddressSanitizer (ASan) 是一種編譯器和運行時技術(shù),它通過和編譯器配合,通過插樁技術(shù),向內(nèi)存的前后添加標識,來識別運行時產(chǎn)生的上溢和下溢異常。其對代碼執(zhí)行性能影響較大,VS中默認是關閉的,需要手動打開。
ASan可以識別棧內(nèi)存、堆內(nèi)存、靜態(tài)內(nèi)存的溢出,另外也能檢測重復釋放,釋放后使用內(nèi)存。
通過C/C++->General->Enable Address Sanitizer使能,此配置與編輯并繼續(xù)、增量鏈接和/RTC不兼容。

更多信息:AddressSanitizer | Microsoft Learn
資源泄露
電腦上的內(nèi)核資源是有限的,申請使用完了,就要釋放,否則資源可能不夠用,導致后續(xù)申請失敗而運行異常。所以資源泄露也是比較嚴重的問題,需要解決。
10. 內(nèi)存泄露
在調(diào)試運行進程時,退出調(diào)試后,可能會在VS的Output窗口中顯示如下信息:

這就是內(nèi)存泄露的提示信息。上面的信息有時會指出內(nèi)存泄露的位置,有的時候指出的位置卻不準確。第三方工具 Visual Leak Detector,可以用來檢測內(nèi)存泄露,其主要是通過重載內(nèi)存申請和釋放函數(shù),然后記錄內(nèi)存申請的地址和詳細源文件行號,最后退出時檢測所有申請的地址是否釋放,如果沒有釋放,則打印出內(nèi)存申請的信息。
Visual Leak Detector的使用非常簡單,下載安裝,然后在工程的啟動接口文件中添加#include <vld.h>即可。
詳細信息見:Home · KindDragon/vld Wiki · GitHub
10.1. 句柄泄露
除了內(nèi)存泄露外,句柄也是容易泄露的資源。
可以使用WinDbg的句柄快照對比功能找出未正常釋放的句柄。
可以使用第三方工具Deleaker,可以注冊試用版本使用14天。Deleaker會檢測出代碼申請未釋放的行號。

11. 靜態(tài)調(diào)試
相比于動態(tài)調(diào)試(在代碼運行時調(diào)試),靜態(tài)調(diào)試是在代碼編譯時來調(diào)試,其效率更高。
11.1. 靜態(tài)斷言
靜態(tài)斷言static_assert是C++11中引入的新語法,可以在編譯時進行一些判斷,并打印相應信息。
static_assert(sizeof(int) == 4, "int must be 4 bytes"); // 檢查 int 類型是否為 4 字節(jié)
template <typename T>
void process(T value) {
static_assert(std::is_integral<T>::value, "T must be an integral type"); // 檢查模板類型是否為整數(shù)類型
}11.2. 靜態(tài)分析
VS自帶的靜態(tài)分析,功能非常強大,能夠發(fā)現(xiàn)很多隱藏的問題。開啟靜態(tài)分析之后,會在編譯期間進行靜態(tài)分析代碼,所以會加大編譯時間。建議定期開啟靜態(tài)分析檢查代碼,并修復相關問題。

另外還可以選擇相應的靜態(tài)分析規(guī)則:

12. 性能調(diào)試
VS提供了性能度量工具(Performance Profiler),幫助開發(fā)者優(yōu)化代碼和提高應用程序性能。Profiler的主要功能是診斷內(nèi)存、CPU 使用率。Debug下的性能分析,因為有很多調(diào)試及優(yōu)化的影響,所以很不準確,建議是在Release版本下進行性能調(diào)試分析。
通過Debug->Performance Profiler。C/C++更多用來分析CPU和Memory。

點擊Start之后,目標程序開始執(zhí)行,并開始監(jiān)控性能,并通過Take Snapshot給當前進程拍攝快照。

12.1. 內(nèi)存分析
通過Stop Collection或等進程結(jié)束,會顯示如下信息。每個快照會保存詳細的進程堆棧信息。

點擊上面的內(nèi)存分配次數(shù)、分配次數(shù)增量等數(shù)據(jù),可以獲取詳細信息:

雙擊相應對象分配行,可以得到詳細的對象信息包括調(diào)用堆棧信息,通過調(diào)用??梢圆榭聪鄳拇a:

12.2. CPU分析

內(nèi)存分類統(tǒng)計:

內(nèi)存分線程統(tǒng)計:

雙擊函數(shù)名,可以詳細函數(shù)占比分析:

12.3. 性能提示
調(diào)試器在斷點或單步執(zhí)行操作中停止執(zhí)行時,中斷與上一個斷點之間經(jīng)過的時間會顯示為在編輯器窗口中的提示。

更多信息見:在 Visual Studio 中度量性能 - Visual Studio (Windows) | Microsoft Learn
協(xié)同調(diào)試
VS提供了多人協(xié)作進行調(diào)試的功能,使用非常簡單。
登錄VS帳號。
點擊如下圖中紅圈的圖標,啟用協(xié)作會話。

協(xié)作會話啟動完成后,會顯示如下信息。默認已經(jīng)將協(xié)作邀請鏈接進行了拷貝。如果協(xié)作方只需要查看代碼,不需要調(diào)試,可以點擊Make read-only。

將協(xié)作邀請鏈接發(fā)給協(xié)作方并打開,彈出如下窗口。

打開VS Code,主持人開始調(diào)試,協(xié)作方也可以通過VS Code查看調(diào)試信息。

通過VS的File->Join Live Share Session來加入?yún)f(xié)作調(diào)試。
還可以進行協(xié)作的管理,以及協(xié)作時聊天。

14. 調(diào)試技巧
14.1. 小技巧
使用快捷鍵,另外還可以自定義快捷鍵。
固定數(shù)據(jù)提示信息

格式化內(nèi)存
調(diào)試器也能在 Watch 窗口中顯示格式化的內(nèi)存值,高達 64 個字節(jié)。你能用下面的說明符在表達式(變量或內(nèi)存地址)后來格式化數(shù)據(jù)。
mb / m - BYTE
mw - WORD
md - DWORD
mq – 8BYTE
ma – 16BYTE

14.2. 管理員權(quán)限調(diào)試
通過Linker->Manifest File->UAC Execution Level->requireAdministrator,啟用管理員權(quán)限,然后啟用調(diào)試,則被調(diào)試的進程也將獲取管理員權(quán)限。
14.3. 生成調(diào)用棧信息
void printStackTrace()
{
HANDLE process = GetCurrentProcess();
SymInitialize(process, nullptr, TRUE);
void* stack[100];
WORD frames = CaptureStackBackTrace(0, 100, stack, nullptr);
SYMBOL_INFO* symbol = (SYMBOL_INFO*)malloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char));
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
for (WORD i = 0; i < frames; ++i) {
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
printf("[%d] %s\n", i, symbol->Name);
}
free(symbol);
}
14.4. 內(nèi)存耗盡
Windows下的32位應用程序,只能申請2GB內(nèi)存。所以在申請過的總內(nèi)存過大時,可能超過2GB,導致程序異常??梢允褂孟旅娲a提示總內(nèi)存過大的提示。
void NoMoreMemory()
{
LPVOID lpMsgBuf;
if (!FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
0x00000008, // Memory error
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL ))
{
return;
}
// Display the string.
MessageBox( NULL, (LPCTSTR)lpMsgBuf, _T("Error"), MB_OK | MB_ICONINFORMATION );
abort();
}
// Add to this function to the entry of EXE/DLL.
set_new_handler(NoMoreMemory);14.5. 未初始化異常
14.5.1. Debug
VS在Debug下為了方便用戶調(diào)試,編譯器會強制將未初始化的變量強制賦值指定值做標記。
棧變量強制賦值0xCCCCCCCC,堆內(nèi)存強制賦值為0xCDCDCDCD。
14.5.2. Release
在VS下,C/C++中的變量編譯器不會對變量進行初始化。棧變量和堆內(nèi)存都是隨機的。養(yǎng)成變量初始化的習慣是提升代碼質(zhì)量的好習慣。
14.6. 調(diào)試運行時庫代碼
VS運行時庫,有一些提供了代碼,有一些沒有提供。如CString的GetLength()函數(shù)。VS2012及之前的版本默認不會進入庫函數(shù),VS2015及之后版本默認在使用Step Into時會進入庫函數(shù)。如果無法進入庫函數(shù),可以進入?yún)R編調(diào)試,然后再Step Into就可以進入庫函數(shù)了。

14.7. Debug和Release的差異
編譯優(yōu)化:
Debug 模式下,編譯器不會進行任何優(yōu)化,以便于調(diào)試和錯誤定位。
Release 模式下,編譯器會進行各種優(yōu)化,以提高程序的性能和執(zhí)行效率。
調(diào)試信息:
Debug 模式下,編譯器會生成完整的調(diào)試信息,包括變量名、行號等,方便進行調(diào)試。
Release 模式下,編譯器會盡量減少調(diào)試信息的生成,以減小程序的體積。
運行時檢查:
Debug 模式下,編譯器會添加額外的運行時檢查,如數(shù)組越界檢查、內(nèi)存泄漏檢查等,以幫助發(fā)現(xiàn)程序中的錯誤。
Release 模式下,這些運行時檢查通常會被禁用,以提高程序的執(zhí)行速度。
斷言和異常處理:
Debug 模式下,程序會更加嚴格地檢查各種斷言和異常,以幫助開發(fā)者發(fā)現(xiàn)問題。
Release 模式下,這些檢查通常會被禁用或簡化,以提高程序的穩(wěn)定性和性能。
編譯器定義宏:
Debug 模式下,編譯器會定義
_DEBUG宏,用于在代碼中進行條件編譯。Release 模式下,編譯器會定義
NDEBUG宏,用于在代碼中進行條件編譯。
編譯器優(yōu)化標志:
Debug 模式下,編譯器通常會使用
/Od標志禁用優(yōu)化。Release 模式下,編譯器通常會使用
/O2標志啟用最高級別的優(yōu)化。
鏈接器優(yōu)化:
Debug 模式下,鏈接器通常不會進行任何優(yōu)化。
Release 模式下,鏈接器會進行各種優(yōu)化,如去除未使用的函數(shù)和數(shù)據(jù)等。
運行時庫:
Debug 模式下,程序會鏈接到 Debug 版本的運行時庫,提供更多的錯誤檢查和調(diào)試支持。
Release 模式下,程序會鏈接到 Release 版本的運行時庫,以提高性能和減小程序體積。
14.8. 構(gòu)建事件
有時需要在編譯前后附加一些操作來簡單調(diào)試,就可以使用編譯事件配置,選擇相應的構(gòu)建事件然后配置命令行來執(zhí)行需要附加的操作。

14.9. 日志
日志是調(diào)試工具的重要手段,除了使用Trace和OutputDebugString之外,還可以使用自定義的日志函數(shù)。
14.10. 調(diào)試窗口
VS自帶的Spy++可以用來查看窗口信息,還可以用來監(jiān)控窗口消息。

14.11. 查看DLL接口
dumpbin是VS自帶的命令行工具,可以用來查看DLL的接口函數(shù)。通過Tools->Command Line來使用。
這是一個命令行工具,可以用于查看 DLL 文件的結(jié)構(gòu)和內(nèi)容。常用命令:
dumpbin /exports <DLL_FILE_PATH>: 查看 DLL 的導出函數(shù)dumpbin /dependents <DLL_FILE_PATH>: 查看 DLL 的依賴項dumpbin /headers <DLL_FILE_PATH>: 查看 DLL 的頭部信息
15. 總結(jié)
調(diào)試是手段,不是目的,不能為了調(diào)試而調(diào)試。目的是更高效地開發(fā),為此,減少問題,減少調(diào)試才是最重要的。
到此這篇關于Visual Studio調(diào)試C/C++教程指南的文章就介紹到這了,更多相關Visual Studio調(diào)試C++內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
OpenCV實現(xiàn)彩色照片轉(zhuǎn)換成素描卡通片
這篇文章主要為大家詳細介紹了OpenCV實現(xiàn)彩色照片轉(zhuǎn)換成素描卡通片,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01
c/c++?Error:?redefinition?of?'xxx'的問題及解決方法
兩個類/文件同時引用定義ReplyInfo的頭文件,會造成頭文件中定義重復定義,本文給大家分享c/c++?Error:?redefinition?of?‘xxx’?的問題及解決方法,感興趣的朋友一起看看吧2023-08-08

