盤錦網(wǎng)站建設(shè)價(jià)位軟件開發(fā)網(wǎng)站
前言
我們已經(jīng)學(xué)習(xí)了
linux
下許多的工具,vim
、gcc
、make/makefile
等;已經(jīng)能夠在
linux
寫代碼,并且進(jìn)行編譯運(yùn)行,讓程序在linux
下跑起來。
但是,如果我們?cè)趯懘a的時(shí)候遇見了錯(cuò)誤;但是我們并不知道錯(cuò)誤在哪,在windows
下,我們可以進(jìn)行調(diào)試來查找代碼錯(cuò)誤的位置進(jìn)行修改;我們?cè)?code>linux就只能查看源代碼,直接查找錯(cuò)誤,這樣很麻煩;
現(xiàn)在就來學(xué)習(xí)linux
如何調(diào)試程序。
調(diào)試程序 ——gdb/cgdb
Debug/Release
模式
在之前學(xué)習(xí)C語言
時(shí),聽說過Debug
和Release
,只知道Debug
時(shí)用來調(diào)試的,程序員寫代碼的版本;而Release
是發(fā)布版本。
現(xiàn)在我們來看一下這兩個(gè)模式有什么區(qū)別
- 首先的區(qū)別就是
Debug
會(huì)生成程序的調(diào)試信息,而Release
不會(huì)生成程序的調(diào)試信息。
因?yàn)?code>Debug模式會(huì)生成調(diào)試信息,所以Debug
模式的程序就要比Release
模式的程序大小要大。
我們?nèi)绾悟?yàn)證呢?
linux
中 gcc
編譯默認(rèn)生成的是Release
版本,我們要生成Debug
模式就要帶-g
選項(xiàng)。
現(xiàn)在有這樣一段代碼test.c
文件
#include<stdio.h>
int func(int n)
{int ret = 0;for (int i = 1; i <= n; i++){ret += i;}return n;
}
int main()
{int n = 100;int sum = func(n);printf("sum = %d\n", sum);return 0;
}
我們?cè)?code>linux下進(jìn)行編譯
這里有這樣的提示,那是因?yàn)?code>C98不支持在for
循環(huán)中定義變量,要使用C99
,上面也有提示。
所以我們就要這樣來編譯
gcc test.c -o test -st=c99
這里寫成makefile
方便操作。
這樣生成的是Release
模式的程序,我們查看它文件屬性
現(xiàn)在,我們使用-g
選項(xiàng)生成Debug
模式的程序
可以看到Debug
模式的要比Release
模式的程序要大一些。
gdb
/cgdb
的使用
這里,只有Debug
模式的程序才能被調(diào)試;Release
模式下不能被調(diào)試,因?yàn)槿鄙僬{(diào)試信息。
在使用之前可能需要進(jìn)行安裝
yum -install -y gdb
yum -install -y cgdb
1. 進(jìn)入調(diào)試
gdb 可執(zhí)行程序
這里無論是gdb
還是cgdb
,都是可執(zhí)行程序,對(duì)可執(zhí)行程序進(jìn)行調(diào)試。
可以看到這樣就進(jìn)入gdb
調(diào)試了,但是gdb
調(diào)試現(xiàn)在看不到我們的源代碼。
2. 退出調(diào)試
quit
現(xiàn)在來看一下cgdb
調(diào)試的界面
cgdb test
這樣的界面看起來要比gdb
好用一些,所以這里就以cgdb
為例,來學(xué)習(xí)調(diào)試
cgdb
中,屏幕上半部分可以看到一部分代碼;其中綠色箭頭
指向的地方就是當(dāng)前程序運(yùn)行的位置。
退出調(diào)試仍然是quit
3. 查看代碼
查看代碼,l
;后可以什么的不跟,也可以跟行號(hào)或者函數(shù)名
l
:查看源代碼,從上次位置開始,依次顯示10
行代碼l 文件名:行號(hào)
:列出指定文件的源代碼l 函數(shù)名
:列出指定函數(shù)的源代碼
l 文件名:行號(hào)
l:函數(shù)名
這里列出的可能有一些差別。
4. 運(yùn)行代碼
我們進(jìn)入調(diào)試,但是代碼并沒有運(yùn)行起來;在windows
下我們之間F5
就讓代碼運(yùn)行起來了;而cgdb
中r
命令可以讓代碼運(yùn)行起來
r/run
,執(zhí)行代碼:
逐步執(zhí)行
有了斷點(diǎn),我們?cè)?code>r時(shí)程序就會(huì)停止在斷點(diǎn)處,那我們?cè)撊绾我恍幸恍袌?zhí)行代碼呢?
在
windows
下,我們是按F10
和F11
來依次執(zhí)行代碼;在
linux
中cgdb
,我們使用n/next
和s/step
來依次執(zhí)行代碼
n/next
,相當(dāng)于F10
,一行一行執(zhí)行代碼, 在遇到函數(shù)時(shí),不進(jìn)入函數(shù)內(nèi)部;
s/step
,就相當(dāng)于F11
,一行一行執(zhí)行代碼, 在遇到函數(shù)時(shí),進(jìn)入函數(shù)內(nèi)部;
這里就不演示了。
執(zhí)行到某處
在我們調(diào)試程序時(shí),程序現(xiàn)在停止在一個(gè)斷點(diǎn)處,我們不想一行一行執(zhí)行代碼,而是想要讓程序直接運(yùn)行到下一個(gè)代碼;
只需要指向
c/contine
即可
c/continue
r
重新執(zhí)行
如果現(xiàn)在程序正在執(zhí)行,我們想要讓程序重新執(zhí)行,只需要
r
即可;這是會(huì)詢問我們是否重新執(zhí)行,
y
即可
finish
執(zhí)行到當(dāng)前函數(shù)結(jié)束,然后停止
until
執(zhí)行到某一行
until 行號(hào)
程序執(zhí)行到某一行然后停止。
現(xiàn)在執(zhí)行until 11
,讓程序執(zhí)行到11
行。
5. 斷點(diǎn)
增加/刪除斷點(diǎn)
我們指向
run/r
后,發(fā)現(xiàn)代碼直接就執(zhí)行結(jié)束了;但是在我們調(diào)試的時(shí)候,我們并不希望代碼執(zhí)行運(yùn)行結(jié)束,我們需要通過斷點(diǎn)讓代碼在指定位置停下來;
在windows
下,我們通過快捷鍵F9
或者鼠標(biāo)點(diǎn)擊來打斷點(diǎn)和去掉斷點(diǎn);
在cgdb
中,我們通過命令**b/break
**來打斷點(diǎn),通過delete/d
來取消斷點(diǎn)。
b
打斷點(diǎn)
b 行號(hào)
:在指定行打斷點(diǎn)b 函數(shù)名
:在函數(shù)開頭打斷點(diǎn)
可以看到,我們打斷點(diǎn)之后并看不到任何斷點(diǎn)信息,那如果我們想要看到已經(jīng)存在的斷點(diǎn),可以使用命令
info b
來查看
info b
查看所有斷點(diǎn)信息
d
刪除斷點(diǎn)
我們打斷點(diǎn)可以通過
行號(hào)
,但是刪除斷點(diǎn)我們就不能使用行號(hào)了,而是使用Num
斷點(diǎn)編號(hào)。
這里還要注意一個(gè)點(diǎn),斷點(diǎn)編號(hào)時(shí)不斷遞增的,不會(huì)隨著我們刪除斷點(diǎn)而減小
什么意思呢,就是現(xiàn)在存在兩個(gè)斷點(diǎn)我們刪除了其中一個(gè)斷點(diǎn),然后再次創(chuàng)建了一個(gè)斷點(diǎn),它的編號(hào)就是3
而不是2
。
這樣有了斷點(diǎn),我們?cè)趫?zhí)行
r
時(shí)就程序就會(huì)停止在斷點(diǎn)處。
這里看一下上半代碼部分,可以看到程序停在了
15
行,并且斷點(diǎn)位置的行號(hào)顏色為紅色。
啟用/禁用斷點(diǎn)
當(dāng)我們?cè)谡{(diào)試程序時(shí),我們?cè)黾拥臄帱c(diǎn)并不一定所有的都能用的到,有一些斷點(diǎn)我們不想讓它在這次調(diào)試中起作用,這時(shí)就可以禁用這個(gè)斷點(diǎn)
看到這里可能有疑惑,為什么不直接刪除呢?
如果代碼非常的多,刪除了之后,接下來調(diào)試要用到,又要重新去找,非常浪費(fèi)時(shí)間。
啟用斷點(diǎn)
enable 斷點(diǎn)編號(hào)
禁用斷點(diǎn)
disable 斷點(diǎn)編號(hào)
這里斷點(diǎn)默認(rèn)是啟用狀態(tài)的。
那現(xiàn)在執(zhí)行一下看是否真的禁用了呢?
可以看到第一個(gè)斷點(diǎn)并未觸發(fā),而是直接觸發(fā)第二個(gè)斷點(diǎn)。
6. 監(jiān)視
在windows
下我們通過監(jiān)視窗口來查看一個(gè)變量的值;
而在linux
的cgdb
中,我們也可以通過指令來查看變量的值。
監(jiān)視變量
p
p
用來查看一個(gè)變量當(dāng)前的值
但是這樣,我們?cè)诖藞?zhí)行代碼會(huì)發(fā)現(xiàn),執(zhí)行過后就不在顯示了;
這樣我們每次查看就要去輸入指令
p 變量名
,這樣好麻煩,我們想要每一次執(zhí)行過后,它都會(huì)顯示出來變量的值
display
用來跟蹤顯示變量的值。
display
如上圖所示,我們每一次執(zhí)行代碼,變量的值都會(huì)顯示出來。
監(jiān)視函數(shù)棧幀內(nèi)局部變量
如果我們不是想要查看某一個(gè)變量,而是查看當(dāng)前函數(shù)內(nèi)所有的局部變量?
我們就要用到info/i locals
可以看到func
中所有的局部變量都顯示出來了。
查看當(dāng)前函數(shù)調(diào)用棧幀
如果我們想要查看當(dāng)前的函數(shù)調(diào)用棧幀,直接使用
bt/backtrace
即可。
cgdb
常用小技巧
1. watch
watch
:用來監(jiān)視一個(gè)變量的值是否發(fā)生變化,發(fā)生變化時(shí)會(huì)提示。
我們使用info b
查看斷點(diǎn)中也可以看到watch
監(jiān)視的變量。
2. set war
set war
:在調(diào)試過程中,修改變量的值。
可以看到,我們?cè)谡{(diào)試過程中,使用set var
就可以修改一個(gè)變量的值。
3. 條件斷點(diǎn)
添加條件斷點(diǎn)
b 行號(hào) if 條件
如上圖所示,新添加的條件斷點(diǎn)(當(dāng)i==10
時(shí)觸發(fā))。
可以看到程序在i==0
時(shí),斷點(diǎn)觸發(fā),停止在第九行。
給已存在斷點(diǎn)增加條件
當(dāng)我們需要給已經(jīng)存在的斷點(diǎn)增加條件時(shí),我們需要指令
condition 斷點(diǎn)編號(hào) 條件
到這里本篇內(nèi)容就結(jié)束了,希望對(duì)你有所幫助。
制作不易,感謝大佬的支持。
我的博客即將同步至騰訊云開發(fā)者社區(qū),邀請(qǐng)大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws