在程序開發中,調試是定位和解決問題的核心環節。GDB (GNU Debugger) 作為一款功能強大的命令行調試器,是Linux環境下C/C++開發者的必備利器。本文將系統講解GDB的使用方法,涵蓋基礎操作到高級技巧,助你高效排錯。
一、基礎準備:編譯與啟動
1. 程序發布模式與調試信息
- Debug模式: 編譯器保留完整調試信息(符號表、行號等),便于調試。程序體積較大,運行效率稍低。
- Release模式: 編譯器進行深度優化,去除調試信息,生成體積小、運行快的程序,不適合直接調試。
關鍵點: 要使用GDB調試,編譯時必須顯式添加 -g
選項,生成包含調試信息的可執行文件。
gcc -g test.c -o test # 編譯包含調試信息的可執行程序 'test'
g++ -g myapp.cpp -o myapp # C++ 同理
2. 啟動與退出 GDB
- 啟動:
gdb <可執行文件名>
gdb test # 調試名為 'test' 的程序
- 退出:
- 輸入命令:
quit
或q
- 快捷鍵:
Ctrl + D
- 輸入命令:
二、核心調試命令詳解
1. 查看源代碼 (list
/ l
)
l [行號]
: 從指定行號開始顯示源代碼(默認顯示當前上下文10行)。l 15
: 顯示第15行附近的代碼。- 連續輸入
l
或按 Enter 鍵繼續向下顯示。
l [函數名]
: 顯示指定函數的源代碼。l main
: 顯示main
函數的代碼。
2. 運行控制
命令 | 縮寫 | 作用 |
---|---|---|
run | r | 開始/重新開始運行程序。遇到斷點暫停,無斷點則運行到結束。 |
next | n | 單步執行(不進入函數)。執行下一行代碼,將函數調用當作一步執行完。 |
step | s | 單步進入。執行下一行代碼,進入被調用函數的內部。 |
continue | c | 繼續運行。從當前暫停處繼續執行,直到遇到下一個斷點或程序結束。 |
finish | fin | 執行完當前函數。運行到當前函數返回,并暫停在調用該函數的位置。 |
until [行號] | u | 運行到指定行。用于跳過循環或快速到達代碼中的特定位置。 |
3. 斷點管理 (break
/ b
)
- 設置斷點:
b [行號]
: 在指定行設置斷點。b 20
b [函數名]
: 在函數入口處設置斷點。b calculate
- 查看斷點:
info breakpoints
(i b
) - 刪除斷點:
delete [斷點編號]
(d [編號]
): 刪除指定編號斷點。d 2
delete
(d
): 刪除所有斷點。
- 禁用/啟用斷點:
disable [斷點編號]
: 禁用斷點(斷點存在但無效)。enable [斷點編號]
: 啟用被禁用的斷點。
4. 變量操作
- 查看值:
print [變量名]
(p [變量名]
)p sum
: 打印變量sum
的當前值。p &sum
: 打印變量sum
的地址。p *ptr
: 打印指針ptr
指向的值。
- 修改值:
set var [變量名]=[值]
set var count=0
: 將變量count
設置為 0。
- 自動顯示:
display [變量名]
: 每次程序暫停時自動顯示該變量的值。info display
: 查看當前設置的所有自動顯示項及其編號。undisplay [編號]
: 取消指定編號的自動顯示。
5. 其他常用命令
backtrace
(bt
): 查看調用棧。顯示當前執行位置及其調用路徑(棧幀),極其重要!frame [棧幀編號]
(f [編號]
): 切換棧幀。配合bt
使用,查看不同函數調用層的上下文。info locals
(i locals
): 查看當前棧幀的局部變量。info args
(i args
): 查看當前函數的參數值。
三、高級調試技巧
1. 多線程調試
info threads
(i threads
): 列出所有線程,顯示線程ID、狀態和當前執行位置。thread [線程ID]
(t [ID]
): 切換到指定線程進行調試。t 3
thread apply [線程ID] [命令]
: 對指定線程執行命令。thread apply 3 bt
: 查看線程3的調用棧。
thread apply all [命令]
: 對所有線程執行命令。thread apply all bt
: 查看所有線程的調用棧(非常有用!)。
- 線程調度鎖:
set scheduler-locking on
: 鎖定當前線程。只有當前調試的線程會執行,其他線程暫停,避免干擾。set scheduler-locking off
: 解除鎖定(默認狀態)。所有線程正常調度執行。set scheduler-locking step
: 僅在單步執行(n
,s
)時鎖定當前線程,run
/continue
時其他線程可運行。
2. 調試核心轉儲 (Core Dump)
核心轉儲記錄了程序崩潰瞬間的內存狀態,是事后調試的關鍵。
- 啟用核心轉儲生成:
ulimit -c unlimited # 在當前Shell會話中設置核心轉儲文件大小無限制
- 提示: 有時需要配置系統參數(如
/proc/sys/kernel/core_pattern
)來指定核心文件路徑和命名規則。
- 提示: 有時需要配置系統參數(如
- 程序崩潰后,通常會在當前目錄或指定位置生成名為
core
或core.[pid]
的文件。 - 使用GDB加載核心文件:
gdb <可執行文件名> <核心文件名>
gdb myapp core.12345 # 調試 'myapp' 程序,加載核心文件 'core.12345'
- 加載后,立即查看崩潰點:
bt
: 查看崩潰時的完整調用棧,定位問題函數和行號。f [棧幀編號]
: 切換到相關棧幀。p [變量]
/i locals
: 檢查崩潰點的變量狀態。
四、總結與最佳實踐
GDB 是程序調試的瑞士軍刀,熟練掌握它能極大提升排錯效率。關鍵點在于:
- 編譯加
-g
: 調試的基石,沒有調試信息寸步難行。 - 善用斷點 (
b
) 與運行控制 (r
,n
,s
,c
): 控制程序執行流程。 - 洞察變量狀態 (
p
,display
,info locals
): 理解程序內部數據變化。 - 利用調用棧 (
bt
,f
): 理清代碼執行路徑,快速定位問題源頭。 - 掌握高級技巧:
- 多線程調試 (
info threads
,thread
,scheduler-locking
) 解決并發問題。 - 核心轉儲調試 (
gdb <exe> <core>
,bt
) 用于事后分析崩潰原因。
- 多線程調試 (
- 勤加練習: 結合真實項目中的Bug進行調試是掌握GDB的最佳途徑。
小貼士:
- 使用
.gdbinit
文件可以定制 GDB 啟動行為(如預加載命令、設置別名)。 - GDB 支持命令補全(按
Tab
鍵)和歷史命令(上下箭頭鍵)。 - 探索
help [命令]
獲取命令的詳細幫助信息。
通過系統學習和實踐這些技巧,你將能夠更加自信和高效地使用 GDB 征服程序中的各種疑難雜癥,顯著提升開發質量和效率!