一、前言
- 學(xué)習(xí)了【vim】知道了如何編輯一個代碼文本
- 學(xué)習(xí)了【gcc】知道了如何編譯一個代碼文本
- 學(xué)習(xí)了【make/Makefile】知道了如何自動化構(gòu)建一個代碼文本
但是如何對一段代碼去進(jìn)行調(diào)試呢,此時就要使用到Linux下的調(diào)試器gdb
了。對于這個調(diào)試器來說,不像是VS中那樣的圖形化界面形式,而是采用純命令行的形式進(jìn)行調(diào)試??赡芪业闹v解會比較晦澀難懂,在學(xué)習(xí)的過程中主要是會一些gdb下基本的操作即可
二、調(diào)試版本與發(fā)布版本
1、見見gdb
下面是本次調(diào)試所要使用到的代碼
1 #include <stdio.h>
2
3 int AddToTop(int top)
4 {
5 printf("Enter AddToTop\n");
6
7 int count = 0;
8 for(int i = 1;i <= top; ++i)
9 {
10 count += i;
11 }
12
13 printf("Quit AddToTop\n");
14 return count;
15 }
16
17 int main(void)
18 {
19 int top = 100;
20 int ret = AddToTop(top);
21
22 printf("ret = %d\n", ret);
23 return 0;
24 }
下面是Makefile中的內(nèi)容,用于自動化編譯
1 mytest:test.c
2 gcc -o mytest test.c -std=c99
3 .PHONY:clean
4 clean:
5 rm -rf mytest
注:-std=c99
表示以c99的標(biāo)準(zhǔn)來編譯代碼
- 如果要進(jìn)入gdb開始調(diào)試,那直接
gdb + 可執(zhí)行程序
即可 - 不過進(jìn)去之后發(fā)現(xiàn)似乎有一些奇怪的內(nèi)容,【no debugging symbols found】,翻譯過來就是沒有調(diào)試信息。那這是為何呢?是gdb出問題了嗎?
- 先不要著急,如果有經(jīng)常調(diào)試的同學(xué)就可以知道只有在【DeBug】的環(huán)境下才會有我們想要的調(diào)試信息,所以可以初步推斷這可能不是一個【DeBug】版本的可執(zhí)行程序
- 先使用
q(quit)
退出gdb
讓我們先看下去,了解一下其他的知識再來解決這個問題
2、程序員與測試人員
接下去我們就來說說有關(guān)【DeBug】和【Release】版本的不同之處
??【Debug】—— 調(diào)試版本
??【Release】—— 發(fā)布版本
- 在使用VS的時候我們可以直接使用鼠標(biāo)來進(jìn)行操作,當(dāng)前程序以DeBug或者是Release的形式進(jìn)行運(yùn)行,那么運(yùn)行出來的可執(zhí)行程序版本也是不同的,我們程序員在編寫代碼后運(yùn)行一般是使用【DeBug】環(huán)境進(jìn)行運(yùn)行。因為在企業(yè)里寫軟件項目,將代碼寫完后程序員自己要做簡單的測試,保證代碼沒有問題
- 當(dāng)程序員自己測試完沒有問題之后,就會將這個可執(zhí)行程序給到
測試人員
進(jìn)行測試,而且會給出自己的單元測試報告。對于測試人員來說所處的模式是【Release】,也就是將來客戶要使用的這款軟件的發(fā)布版本 - 當(dāng)測試在測的過程中,一定會發(fā)現(xiàn)一些問題。此時測試人員就會把報告再打回研發(fā)部。研發(fā)部做修改重新生成Release版本的可行性程序給到測試人員繼續(xù)測試
- 最后只有當(dāng)測試通過了,再將生成的【單元測試報告】與產(chǎn)品經(jīng)理進(jìn)行核對之后沒有問題,那這個軟件才可以真正地面向市場??
3、為什么Release不能調(diào)試但DeBug可以調(diào)試?
其實對于我們剛才直接make自動化生成的可執(zhí)行程序是通過gcc直接編譯產(chǎn)生得到的,它是一個【Release】版本的可執(zhí)行程序,因此無法進(jìn)行調(diào)試
- 若是我們想要使用
gcc/g++
去生成一個可執(zhí)行程序時,默認(rèn)是【Release】版本的,而不是【DeBug】 - 但若是我們想要去生成一個【DeBug】版本的可執(zhí)行程序也是可以的,只需要修改一下我們的Makefile即可,給gcc后面帶上一個
-g
的命令選項,此時再去make一下的話生成的就是【DeBug】版本的了
- 為了之前的【Release】版本不被覆蓋,我們將其重命名一下為
mytest-release
- 在生成【DeBug】版本后一樣對其進(jìn)行一個重命名為
mytest-debug
-
通過觀察上圖中兩個可執(zhí)行文件的大小便可以發(fā)現(xiàn)雖然它們都是可執(zhí)行程序,但是容量大小卻不一樣,這是為什么呢?
-
因為以Release版本發(fā)布的軟件是給客戶的,客戶是不需要調(diào)試信息的
-
往可執(zhí)行程序里添加很多的調(diào)試信息意味著軟件的體積會變大
- 一方面,用戶下載需要時間了
- 另一方面,用戶下載好之后將軟件啟動、運(yùn)行都需要更多的時間,體驗不好。一般能不加就不加
-
但是對于DeBug來說會自動加調(diào)試信息,容量體積比Release大
但是就這么說說太抽象了,我們得看看這個可執(zhí)行文件里的調(diào)試信息究竟是怎樣的??
readelf -S mytest-debug
- 在C生萬物 | 程序環(huán)境和預(yù)處理中,我有說到過對于【可執(zhí)行文件】它是一個二進(jìn)制文件,若是查看它的源碼就可以發(fā)現(xiàn)里面都是一堆亂碼
當(dāng)我們面對一堆二進(jìn)制亂碼措手不及的時候,給大家提到過一個東西叫做readelf
,其實它是Linux中的一個指令,可以用來讀取【elf】格式的文件
- 加上
-S
的命令選項以符號表的形式來進(jìn)行讀取這個文件,就以一個列表的形式展現(xiàn)出了這個帶調(diào)試信息的可執(zhí)行程序 - 下面展現(xiàn)幾個比較常見的。例如這里的
-
.rodata
就是read only data即只讀全局?jǐn)?shù)據(jù)區(qū) -
.data
就是已初始化全局?jǐn)?shù)據(jù)區(qū) -
.bss
就是未初始化全局?jǐn)?shù)據(jù)區(qū)
-
- 不過這些呢是這個可執(zhí)行文件中的所有內(nèi)容,若是我們只是先要查看一些debug的調(diào)試信息,就要對這些東西進(jìn)行一個篩選才行
- 此時就可以使用到
grep
命令來進(jìn)行一個篩選。便可以查看到所有的debug調(diào)試信息了
- 上面是查看【DeBug】版本下的調(diào)試信息,在【Release】版本有沒有呢
- 我們也是讀取并搜尋一下這個文件便可以發(fā)現(xiàn)對于【Release】版本來說是不存在調(diào)試信息的,所以什么都沒有被打印出來
【總結(jié)一下】
- 程序的發(fā)布方式有兩種,debug模式和release模式
- Linux gcc/g++出來的二進(jìn)制程序,默認(rèn)是release模式
-
要使用gdb調(diào)試,必須在源代碼生成二進(jìn)制程序的時候, 加上
-g
選項
好,說到這里,對于調(diào)試相關(guān)背景就全部講完了,接下去我們正式進(jìn)入【gdb】的學(xué)習(xí)??
三、使用gdb調(diào)試代碼
1、指令集匯總
因為這個調(diào)試器是在Linux環(huán)境下的,是純命令行模式,所以會有很多的指令,做好心里準(zhǔn)備??
注:()括號里面是該指令的全稱
l(list) 行號/函數(shù)名
—— 顯示對應(yīng)的code,每次10行
r(run)
—— F5【無斷點直接運(yùn)行、有斷點從第一個斷點處開始運(yùn)行】
b(breakpoint) + 行號
—— 在那一行打斷點
b 源文件:函數(shù)名
—— 在該函數(shù)的第一行打上斷點
b 源文件:行號
—— 在該源文件中的這行加上一個斷點吧
info b
—— 查看斷點的信息breakpoint already hit 1 time【此斷點被命中一次】
d(delete) + 當(dāng)前要刪除斷點的編號
—— 刪除一個斷點【不可以d + 行號】
- 若當(dāng)前沒有跳出過gdb,則斷點的編號會持續(xù)累加
d + breakpoints
—— 刪除所有的斷點
disable b(breakpoints)
—— 使所有斷點無效【默認(rèn)缺省】
enable b(breakpoints)
—— 使所有斷點有效【默認(rèn)缺省】
disable b(breakpoint) + 編號
—— 使一個斷點無效【禁用斷點】
enable b(breakpoint) + 編號
—— 使一個斷點有效【開啟斷點】
- 相當(dāng)于VS中的空斷點
enable breakpount
—— 使一個斷點有效【開啟斷電】
n(next)
—— 逐過程【相當(dāng)于F10,為了查找是哪個函數(shù)出錯了】
s(step)
—— 逐語句【相當(dāng)于F11,】
bt
—— 看到底層函數(shù)調(diào)用的過程【函數(shù)壓?!?/p>
set var
—— 修改變量的值
p(print) 變量名
—— 打印變量值
display
—— 跟蹤查看一個變量,每次停下來都顯示它的值【變量/結(jié)構(gòu)體…】
undisplay + 變量名編號
—— 取消對先前設(shè)置的那些變量的跟蹤排查問題三劍客??
until + 行號
—— 進(jìn)行指定位置跳轉(zhuǎn),執(zhí)行完區(qū)間代碼finish
—— 在一個函數(shù)內(nèi)部,執(zhí)行到當(dāng)前函數(shù)返回,然后停下來等待命令c(continue)
—— 從一個斷點處,直接運(yùn)行至下一個斷點處【VS下不斷按F5】
2、命令演示
看了上面的這些命令后,相信你一定回到了剛開始學(xué)習(xí)Linux指令的時候那種恐懼感,不過沒關(guān)系,我會一一地演示這些指令,讓你在看完本文后有一個基本的調(diào)試能力??
- 首先我們進(jìn)入到gdb,然后它會等待我們輸入指令
? 行號顯示
l(list) 行號/函數(shù)名
—— 顯示對應(yīng)的code,每次10行
- 首先若是直接【L】的話便會隨機(jī)顯示出該源文件中的隨機(jī)10行內(nèi)容,這不是我們想要的
- 若是【L 0】或者是【L 1】的話那就是從第一行開始往下列10行的內(nèi)容
- 注意這里的L是小寫,而且與數(shù)字之間要有一個空格
- 接下去若是想要看到我們所寫的全部代碼,只需要多
Enter
幾次就可以了,gdb會自動記憶你上次敲入的指令
? 斷點設(shè)置
b + 行號
—— 在那一行打斷點
b 源文件:函數(shù)名
—— 在該函數(shù)的第一行打上斷點
b 源文件:行號
—— 在該源文件中的這行加上一個斷點
? 查看斷點信息
info b
—— 查看斷點的信息
- 若是直接執(zhí)行【info】的話,出來的就是所有的調(diào)試信息
- 但若是我們只想查看一下所打的斷點的信息,那就在后面加個
b/breakpoint
來簡要介紹一下斷點的一些字段信息
- Num —— 編號
- Type —— 類型
- Disp —— 狀態(tài)
- Enb —— 是否可用
- Address —— 地址
- What —— 在此文件的哪個函數(shù)的第幾行
- 最后的話就是每個斷點信息的下面這塊
breakpoint already hit 1 time
即此斷點被命中1次
? 刪除斷點
d + 當(dāng)前要刪除斷點的編號
—— 刪除一個斷點【不可以d + 行號】
d + breakpoints
—— 刪除所有的斷點
- 此時若繼續(xù)將這個20行的斷點打上時,就可以發(fā)現(xiàn)其編號為【4】,而并不是從1開始,這是因為我們沒有退出過gdb,所以會持續(xù)上一次的編號繼續(xù)往下
? 開啟 / 禁用斷點
disable b(breakpoints)
—— 使所有斷點無效【默認(rèn)缺省】
enable b(breakpoints)
—— 使所有斷點有效【默認(rèn)缺省】
disable b(breakpoint) + 編號
—— 使一個斷點無效【禁用斷點】
enable b(breakpoint) + 編號
—— 使一個斷點有效【開啟斷點】
其實對于禁用斷點和啟用斷點,VS中也是有的,它叫做【空斷點】。我們一起來看看
? 運(yùn)行 / 調(diào)試
r(run)
—— F5【無斷點直接運(yùn)行、有斷點從第一個斷點處開始運(yùn)行】
- 首先若是將斷點刪除掉,使用【r】指令運(yùn)行的話就會直接運(yùn)行到程序結(jié)束
- 再加上斷點去運(yùn)行的話就會在打的斷點處停下來
? 逐過程和逐語句
n(next)
—— 逐過程【相當(dāng)于F10,為了查找是哪個函數(shù)出錯了】
- 可以看到,我從第一個斷點處也就是20行的位置開始執(zhí)行,按下【n】之后因為在其后即22行有一個斷點,此時就會直接運(yùn)行到斷點處
s(step)
—— 逐語句【相當(dāng)于F11,一次走一條代碼,可進(jìn)入函數(shù),同樣的庫函數(shù)也會進(jìn)入】
- 此時我們按下【s】,也就相當(dāng)于是【step】,讓程序一步一步地走,繼而進(jìn)入了
AddToTop
這個函數(shù),若是你在printf()語句要執(zhí)行時按下【s】的話gdb就會進(jìn)入printf()庫函數(shù)內(nèi)部去執(zhí)行,這里就不展示了
- 接下去我們可以就繼續(xù)【n】,然后進(jìn)行逐過程調(diào)試,來到for循環(huán)中,那么逐過程也就是變量i的累加和計數(shù)器count的累加,所以會反復(fù)執(zhí)行(通過圖中最左側(cè)可以看出是第8行和第10行在反復(fù)執(zhí)行)
- 可以看到后面我沒有再按【n】了,但是依舊會執(zhí)行上面的步驟,這點上面也有提到過,因為gdb會自動化記憶你上一次執(zhí)行過的命令,所以若是不想再敲了,直接
Enter
就可以了
? 打印 / 追蹤變量
p(print) 變量名
—— 打印變量值
- 都執(zhí)行了那么多次了,不知道【i】和【count】發(fā)生了怎樣的變化,將它們打印出來看看吧??
- 通過繼續(xù)執(zhí)行【n】,然后再去打印就可以發(fā)現(xiàn)
i
的值和count
的值發(fā)生了變化
但是你不覺得這樣每次去打印會顯得很繁瑣嗎,那一定會的,所以我們有更好的辦法??
display
—— 跟蹤查看一個變量,每次停下來都顯示它的值【變量/結(jié)構(gòu)體…】
- 我們也可以去追蹤一下這兩個變量的地址,不過可以看到對于地址來說是不會發(fā)生改變的
undisplay + 變量名編號
—— 取消對先前設(shè)置的那些變量的跟蹤
- 但是呢,每次都追蹤打印這么多內(nèi)容又太多了,我想把它們?nèi)∠丝梢詥??答?strong>當(dāng)然是可以的
- 既然有
display
,那就有undisplay
? 查看函數(shù)調(diào)用
bt
—— 看到底層函數(shù)調(diào)用的過程【函數(shù)壓?!?/strong>
- 通過仔細(xì)觀察剛才追蹤的4個變量最左側(cè)的編號,就可以看到它們的排列的順序是倒著的。因為變量i和變量count是我們先追蹤的,它們的地址是我們后追蹤的,所以可以看出這很像是一個壓棧的過程
- 其實不僅是對于它們,
AddToTop
函數(shù)和main
函數(shù)也呈現(xiàn)這樣的關(guān)系。此時我們就可以通過【bt】這個指令來查看函數(shù)壓棧的過程,此時便可以看到因為
? 修改變量的值
set var
—— 修改變量的值
- 對于這個修改變量的值,很像是在VS里調(diào)試之前設(shè)置的那種條件斷點,可以使調(diào)試開始后直接運(yùn)行到此斷點處。不過對于【set var】而言是在調(diào)試過程中進(jìn)行設(shè)置
我們也可以到VS中來看一下條件斷點是如何設(shè)置的
在右擊選擇【條件】后,就可以輸入你本次執(zhí)行代碼想要從哪個條件開始,然后按下Enter,啟動調(diào)試之后就會從你設(shè)置的條件處開始執(zhí)行
排查問題三劍客??
掌握了上面的這些,你就可以在Linux下調(diào)一些簡單的代碼了,不過想做到高效地進(jìn)行調(diào)試,就需要學(xué)習(xí)一下【三劍客】
? 指定行號跳轉(zhuǎn)
until + 行號
—— 進(jìn)行指定位置跳轉(zhuǎn),執(zhí)行完區(qū)間代碼
- 可以看到,當(dāng)前在for循環(huán)內(nèi)容執(zhí)行累加的邏輯,但若是我們一直這么執(zhí)行下去,就沒有時間排錯了,除了上面的哪一種【set var】之外,還有一種方法其實起到直接結(jié)束當(dāng)前循環(huán)的作用,那就是進(jìn)行指定行號跳轉(zhuǎn)
- 通過觀察下圖可以看到,當(dāng)我們運(yùn)行了
until 13
之后,程序直接就給出了我們最終的結(jié)果count,而且即將要執(zhí)行最后的打印語句,說明我們跳轉(zhuǎn)成功了
- 不過呢,在我使用這個【until】的時候,遇到了一個bug,此時我在循環(huán)內(nèi)部,也就是第10行的位置打了一個斷點,用過VS調(diào)試器的都知道一直按F5就可以立即執(zhí)行下一次循環(huán)。
- 我在上面是沒有打上斷點的,所以使用【until】的時候也沒有出現(xiàn)問題,但是在下面我在循環(huán)內(nèi)部設(shè)置了一個斷點,此時再去使用【until 13】進(jìn)行跳轉(zhuǎn)的時候就出現(xiàn)問題了,并沒有馬上跳轉(zhuǎn)到指定的行號,而是接著執(zhí)行循環(huán)中的內(nèi)容
? 強(qiáng)制執(zhí)行函數(shù)
finish
—— 在一個函數(shù)內(nèi)部,執(zhí)行到當(dāng)前函數(shù)返回,然后停下來等待命令
- 有時候我們會有這樣的需求,在初步排查的時候推斷可能是某個函數(shù)內(nèi)部的邏輯出了問題,但是呢又不想一步步地進(jìn)到函數(shù)內(nèi)部進(jìn)行調(diào)試,在VS中其實很簡單,只需要在函數(shù)下方設(shè)個斷點,然后F5直接運(yùn)行到斷點處即可
- 但是在Linux下的gdb中,我們可以使用【finsh】指令來直接使一個函數(shù)執(zhí)行完畢。從下圖我們可以看到,首先【s】進(jìn)到函數(shù)內(nèi)部,接下去我直接使用
finish
,可以看到它直接回到了調(diào)用函數(shù)的位置,returned了一個返回值
- 然后可以看到,在獲取到返回值后,也就直接進(jìn)行了printf打印
? 跳轉(zhuǎn)到下一斷點
c(continue)
—— 從一個斷點處,直接運(yùn)行至下一個斷點處【VS下不斷按F5】
- 這點也是我剛才在上面有提到過的,在VS中,我們要直接跳轉(zhuǎn)到下一個斷點處只修要按下F5即可,那在gdb中該如何操作呢,你需要敲個【c】就可以了
- 從下圖我們可以看出,對于這個指令的用處可謂是非常大,當(dāng)我處于第一個斷點也就是20行的時候,直接敲下【c】,就可以運(yùn)行到第二個斷點處也就是第10行。之后若反復(fù)敲【c】,因為這是一個單語句的循環(huán),所以循環(huán)的下一次還是會執(zhí)行到此處。上面的這兩個功能就和我們在VS中用的F5是一個道理
四、實戰(zhàn)演練:Swap Two Numbers
??紙上得來終覺淺,絕知此事要躬行??
————————————
以下是本次調(diào)試所要使用到的代碼,相信你一定非常熟悉了,也就是使用指針交換兩數(shù),如果想看細(xì)節(jié)講解可以看看我的函數(shù)章節(jié)
1 #include <stdio.h>
2
3 void swap(int* x, int* y)
4 {
5 int t = *x;
6 *x = *y;
7 *y = t;
8 }
9 int main(void)
10 {
11 int a = 10;
12 int b = 20;
13
14 printf("a = %d, b = %d\n", a, b);
15
16 swap(&a, &b);
17
18 printf("a = %d, b = %d\n", a, b);
19 return 0;
20 }
- 首先我們在程序第16行設(shè)置上一個斷點,然后【r】從第15行開始運(yùn)行
- 然后我們使用【s】進(jìn)入到swap函數(shù)中,因為我首先不想調(diào)試,想先立馬看看運(yùn)行結(jié)果,但是此時又已經(jīng)進(jìn)入調(diào)試了,那么我們就可以使用到【finish】來立馬執(zhí)行完這個函數(shù),然后觀察一下結(jié)果
- 可以看到,最后打印出結(jié)果的時候a和b的值確實發(fā)生了交換
- 既然清楚了二者會進(jìn)行一個交換,接下去我們就逐語句【n】進(jìn)行一個單步追蹤吧
- 因為提前看了執(zhí)行結(jié)果,所以我們要重新開始調(diào)試,按下【r】即可,它會詢問你是否需要重新開始調(diào)試,選擇y之后就可以重新從16行開始進(jìn)行調(diào)試
- 首先通過【display】記錄一下兩個變量的值和地址
- 接著按【s】進(jìn)入到swap函數(shù)里,追蹤一下指針x和指針y的內(nèi)容,也就是它們所存放的地址,就可以看到,函數(shù)內(nèi)部已經(jīng)接受到了這兩個變量的地址
- 但是我們后面不想再查看它們了,只需要看值是否被修改,此時就可以取消對它們的跟蹤【undisplay】
- 然后對我們要觀察的值變化繼續(xù)做一個追蹤
- 并且在執(zhí)行完第一個語句
t = *x
時,臨時變量t中已經(jīng)存放了變量a的值,也就是指針?biāo)赶虻哪菈K空間中的值
- 接下去執(zhí)行
*x = *y
,此時*x中的值就發(fā)生了變化,因為指針x可以直接找到變量a的地址,所以可以對其中的內(nèi)容做修改,就變?yōu)榱?0
- 接下去執(zhí)行
*y = t
,同理,指針y可以直接找到變量b的地址,所以可以對其中的內(nèi)容做修改,將原本保存在臨時變量t中的10賦值給到*y,也就修改了其中的內(nèi)容
- 再按【n】的話這個swap函數(shù)就執(zhí)行結(jié)束了,回到了main函數(shù),就可以清楚地看到函數(shù)內(nèi)部的修改帶動了函數(shù)外部值的變化,真正地通過【傳址調(diào)用】交換了兩個數(shù)
敲黑板:重點來了
- 但是我不僅想讓你看到這些,更加重要的一點不知你有沒有發(fā)現(xiàn),剛才我們在main函數(shù)中追蹤的變量a和變量b的值與地址,到了swap()中就不見了,這是為什么呢?
- 其實就是因為兩個函數(shù)的函數(shù)棧幀不同,變量a和變量b位于main函數(shù)的函數(shù)棧幀中;而指針變量x和指針變量y位于swap函數(shù)的函數(shù)棧幀中,是互不相干的,臨時變量除了函數(shù)棧幀就會被銷毀【如果聽不懂這些請看反匯編深挖【函數(shù)棧幀】的創(chuàng)建和銷毀】
- 但是因為在swap()內(nèi)部接受到了外部兩個變量的地址,所以在函數(shù)內(nèi)部就可以通過這兩個指針找到這兩個變量的地址,從而對這兩個空間中的內(nèi)容做一個修改的操作
通過以上的實驗演練,你是否對調(diào)試器GDB的使用更上一層樓??
五、總結(jié)與提煉
最后來總結(jié)一下本文所學(xué)習(xí)的內(nèi)容??
- 在本文的開始,我們在初見GDB的時候發(fā)現(xiàn)了【
no debugging symbols
】的報錯信息,于是便談到了一個可執(zhí)行程序的【DeBug】版本和【Release】版本,知道了對于前者來說是我們程序員使用的環(huán)境,是存在調(diào)試信息的;對于后者來說是測試人員所處的環(huán)境,是不存在調(diào)試信息的。而對于gcc/g++而言默認(rèn)生成的可執(zhí)行程序就是【Release】版本的,因此我們要加上一個-g
命令選項使其在make之后生成一個【DeBug】版本的可執(zhí)行程序,這樣就可以進(jìn)行調(diào)試了 - 接著我們正式進(jìn)入到了調(diào)試器GDB的使用,介紹了很多相關(guān)的指令,這些都是我整理出來的常見指令,其實對于GDB來說還有很多指令,但是真正常用的也就這些,只要你認(rèn)真地看下來,將它們都使用熟練了,相信你的調(diào)試功底會大幅度提升,對你在VS中的調(diào)試也是有所幫助的
- 最后,在學(xué)習(xí)了GDB的許多調(diào)試指令后,我們便進(jìn)行了【Swap Two Numbers】的實戰(zhàn)演練,不僅鞏固了C語言中有關(guān)傳址調(diào)用以及函數(shù)棧幀的相關(guān)指知識,而且使我們對于調(diào)試器GDB的使用更上一層樓↑
以上就是本文要介紹的所有內(nèi)容,感謝您的閱讀??文章來源:http://www.zghlxwxcb.cn/news/detail-784469.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-784469.html
到了這里,關(guān)于Linux | 調(diào)試器GDB的詳細(xì)教程【純命令行調(diào)試】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!