目錄
軟件包管理器——yum
Linux下,軟件的安裝
yum與軟件包的關系
yum命令的運用
1.查看軟件包
2.安裝/刪除軟件包
編輯器——vim
vim的基本概念
vim的基本操作
命令模式命令
移動光標
刪除文字
撤銷上一次操作
跳至指定的行
底行模式命令
編譯器——gcc/g++
預處理
編譯
匯編
鏈接
庫
動態鏈接與靜態鏈接
總結
自動化構建——make/makefile
基本概念
實例
細節
語法擴展
Linux第?個系統程序——進度條
預備知識
練手——倒計時小程序
進度條簡約版
進度條進階版
調試器 - gdb/cgdb
預備知識點
常見命令
watch
條件斷點
新建條件斷點
在新增斷點上設置條件
軟件包管理器——yum
CentOS版本用yum,Ubuntu版本用apt。
Linux下,軟件的安裝
安裝方法有三:
1.源碼安裝。下載程序的源代碼,并進行編譯,得到可執行程序。
2.rpm安裝方式。使用 rpm
命令來安裝 .rpm
格式的軟件包。(不會自動解決依賴關系)
3.yum工具級別安裝。(自動解決依賴關系)
注:這里的依賴關系是指一個軟件可能需要依賴多個庫才能實現。
yum與軟件包的關系
yum命令的運用
1.查看軟件包
[slm@localhost d1]$ yum list | grep lrzsz
lrzsz.x86_64 0.12.20-36.el7 @anaconda
注:
1,x86_64后綴表示64位系統的安裝包、
2.el7表示的是操作系統發行版的版本。el7表示的是centos7
3.base表示的是“軟件源的名稱。
2.安裝/刪除軟件包
sudo yum install -y 要安裝的軟件
sudo yum remove -y 要卸載的軟件
注;安裝要以超級用戶的身份進行,拷貝下來的軟件會在指定的系統目錄中。
編輯器——vim
vim的基本概念
vim有很多中模式但我們掌握三種即可。三種模式分別是:命令模式,插入模式,底行模式。
用一張圖來清晰解決三種模式的切換命令:
三種模式的特點:
命令模式:用命令對文件內容進行刪除或者控制光標的移動等。
插入模式:可以用鍵盤的輸入對文件內容進行修改。
底行模式:文件保存或退出,也可以進行文件替換,找字符串,列出行號等操作。
vim的基本操作
先進入文件 tmp.c
[slm@localhost d1]$vim tmp.c
命令模式命令
移動光標
按「G」:移動到文章的最后
按「 $ 」:移動到光標所在行的“行尾”
按「^」:移動到光標所在行的“行首”
按「w」:光標跳到下個字的開頭
按「e」:光標跳到下個字的字尾
按「b」:光標回到上個字的開頭
按「#l」:光標移到該行的第#個位置,如:5l,56l
按[gg]:進入到文本開始
按[shift+g]:進入文本末端
按「ctrl」+「b」:屏幕往“后”移動?頁
按「ctrl」+「f」:屏幕往“前”移動?頁
按「ctrl」+「u」:屏幕往“后”移動半頁
按「ctrl」+「d」:屏幕往“前”移動半頁
刪除文字
「yw」:將光標所在之處到字尾的字符復制到緩沖區中。
「#yw」:復制#個字到緩沖區
「yy」:復制光標所在行到緩沖區。
「#yy」:例如,「6yy」表示拷貝從光標所在的該行“往下數”6行?字。
「p」:將緩沖區內的字符貼到光標所在位置。注意:所有與“y”有關的復制命令都必須
與“p”配合才能完成復制與粘貼功能。
撤銷上一次操作
「u」:如果您誤執行?個命令,可以馬上按下「u」,回到上?個操作。按多次“u”可以執行
多次回復。
「ctrl + r」: 撤銷的恢復
跳至指定的行
「ctrl」+「g」列出光標所在行的行號。
「#G」:例如,「15G」,表示移動光標至文章的第15行行首。
底行模式命令
列出行號
? 「set nu」: 輸?「set nu」后,會在?件中的每?行前?列出行號。
? 跳到?件中的某?行
? 「#」:「#」號表示?個數字,在冒號后輸??個數字,再按回?鍵就會跳到該行了,如輸?數字
15,再回?,就會跳到?章的第15行。
查找字符
? 「/關鍵字」: 先按「/」鍵,再輸?您想尋找的字符,如果第?次找的關鍵字不是您想要的,可以
?直按「n」會往后尋找到您要的關鍵字為?。
? 「?關鍵字」:先按「?」鍵,再輸?您想尋找的字符,如果第?次找的關鍵字不是您想要的,可
以?直按「n」會往前尋找到您要的關鍵字為?。
保存?件
? 「w」: 在冒號輸?字?「w」就可以將?件保存起來
離開vim
? 「q」:按「q」就是退出,如果?法離開vim,可以在「q」后跟?個「!」強制離開vim。
? 「wq」:?般建議離開時,搭配「w」?起使?,這樣在退出的時候還可以保存文件。???「q!」:不存盤強制退出vim
其他指令:
!man+函數:查詢函數
!command:不離開vim,進入到命令行輸入頁
vs+文件名:一個窗口產生多個文件,如果文件不存在就新建
ctrl+ww:兩個窗口之間關標切換
在命令行模式下批量化注釋:
1.ctrl+v:進入可視化模式
2.按hjkl鍵選擇要注釋的行
3.shift+i=I//進入插入模式
4.按//
5.按兩下Esc鍵
去注釋:
1.ctrl+v:進入可視化模式
2.按hjkl鍵選擇要刪除的部分
3.按d鍵刪除
編譯器——gcc/g++
預處理
作用:進行宏替換/去注釋/條件編譯/頭文件展開等
gcc -E hello.c -o hello.i
//選項”-E“作用是讓gcc在預處理結束后停止編譯過程
//選項”-o“是指目標文件,".i"文件是預處理的C原始程序
注:
1、頭文件展開就是直接把頭文件中相關的內容拷貝到源文件中,所以預處理后就不需要頭文件了
2、條件編譯(#if——#else——#endif),本質是對代碼進行裁剪。比如我們下載軟件的時候有時候會遇到社區版/專業版,在社區版中我們沒有專業版軟件的一些功能,兩個版本的代碼是差不多的,只是兩個版本都新增了一些不同的代碼讓這兩個版本之間產生差別。
3.gcc可以對代碼進行增、刪、改
編譯
作用:檢查代碼的規范性。是否有語法錯誤等,檢查無誤后生成匯編語言。
gcc -S code.i -o code.s
//選項”S“的作用是讓gcc在編譯結束后停止匯編的過程
匯編
作用:生成機器可識別代碼
gcc -c?code.s?-o code.o
//選項”c“的作用是讓gcc在匯編結束后停止鏈接的過程
//不能直接執行,因為.o文件還沒有定位到庫文件中函數的地址,即還沒有把正確的地址補在”地址還不確定的“機器碼上。
鏈接
作用:生成可執行文件或庫文件
gcc hello.o –o hello
//從.c文件直接形成可執行文件
gcc hello.c -o hello //形成hello可執行文件
gcc -o hello hello.c //形成hello可執行文件
gcc hello.c //形成a.out可執行文件
//牢記小秘訣:-o后面都是執行文件。
在上面的鏈接的過程中我們發現想要鏈接成功系統里就必須安裝好庫和頭文件,不然找不到函數的地址,所以為什么要有庫呢?
庫
庫的分類
常見的庫有兩種:動態庫和靜態庫
動態庫:在Linux下,后綴為”.so“;在windows下,后綴為”.dll“
靜態庫:在Linux下,后綴為”.a“;在windows下,后綴為”.lib”
庫的命名
在Linux下,靜態庫:"libXXX.a",其中XXX是靜態庫的名字;動態庫:“libXXX.so”,其中XXX是動態庫的名字。
?兩種庫的區別
靜態庫:會在磁盤進行鏈接時把庫文件的代碼全部加入到可執行文件中(實際上就是拷貝),所以生成的文件比較大,但是運行時不需要庫文件了
動態庫:在編譯鏈接時并沒有把庫文件的代碼加入到可執行文件中,而是在運行可執行文件時鏈接需要的庫文件加載到可執行文件中,這樣可以節省系統的開銷。
兩種庫的優缺點
動態庫 | 靜態庫 | |
優點 | 節省資源 | 不依賴任何庫,可以獨立運行 |
缺點 | 一旦丟失,所有程序無法直接運行 | 體積大,占據資源多,加載速度受影響 |
靜態庫和動態庫的生成
gcc test.c -o test//形成動態鏈接
gcc test.c -o test_static? ?-static//形成靜態鏈接,比動態鏈接占用的空間大
ldd命令是查詢文件依賴的庫文件。
注:gcc默認生成的二進制程序,是動態鏈接的,可以用file命令檢驗。
動態鏈接與靜態鏈接
動態鏈接就是把程序按照模塊拆分成各個相對獨立部分,在程序運?時才將它們鏈接在?起形成?個完整的程序。每個程序里面的庫函數都是共用一個庫的。
靜態鏈接就是把代碼需要的函數直接拷貝到可執行文件中,每個程序里面的庫函數都要拷貝一份庫函數代碼,會產生很多副本。
總結
1.預處理(去注釋/展開頭文件/進行宏替換/條件編譯等)
2.編譯(檢查代碼規范性,檢查語法錯誤,無誤后生成匯編語言)
3.匯編(生成機器可識別二進制代碼)
4.鏈接(生成可執行文件)
5.形成不同階段文件的簡易記法:Esc鍵變成ESc
有時候我們老是代碼寫完了,但是運行的時候會報錯,但是修改完代碼后,又要開始重新形成目標文件,萬一我們的錯誤改了又錯呢,錯很多遍的話這樣就會很麻煩。如果有個文件一直保存這條命令的話那我每次運行的時候就不需要自己又輸一遍了。
自動化構建——make/makefile
基本概念
作用:一旦寫好makefile,只需要一個make命令就可以讓整個工程完全自動編譯,極大提高了軟件開發的效率。
make是解釋makefile文件中指令的命令,所以make是一條命令,makefile是一個文件。
實例
test_9_10:test_9_10.cgcc -o test_9_10 test_9_10.c
.PHONY:clean
clean:rm -f test_9_10
規范:
細節
[root@localhost d1]# ll
總用量 904
drwxr-xr-x. 3 root root 16 3月 13 15:32 d2
-rw-r--r--. 1 root root 89 9月 10 15:30 makefile
-rwxr-xr-x. 1 root root 8664 9月 10 11:13 test
-rw-r--r--. 1 root root 204 9月 10 15:27 test_9_10.c
-rw-r--r--. 1 root root 553 9月 10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月 10 11:13 test_static
[root@localhost d1]# make
gcc -o test_9_10 test_9_10.c
[root@localhost d1]# ll
總用量 916
drwxr-xr-x. 3 root root 16 3月 13 15:32 d2
-rw-r--r--. 1 root root 89 9月 10 15:30 makefile
-rwxr-xr-x. 1 root root 8664 9月 10 11:13 test
-rwxr-xr-x. 1 root root 8416 9月 10 15:31 test_9_10
-rw-r--r--. 1 root root 204 9月 10 15:27 test_9_10.c
-rw-r--r--. 1 root root 553 9月 10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月 10 11:13 test_static
[root@localhost d1]# make
make: “test_9_10”是最新的。
[root@localhost d1]# make clean
rm -f test_9_10
[root@localhost d1]# make clean
rm -f test_9_10
[root@localhost d1]# make clean
rm -f test_9_10
在上面的代碼中我們發現
問題1:make命令后只有一條執行指令,clean怎么不執行?
問題2:make命令執行后后面在執行就會顯示文件是最新的,不會執行,但是clean卻能一直執行
問題一:make、makefile默認只形成一個目標,就是從上到下遇到的第一個目標。但是如果第一條指令中依賴文件列表在該目錄下沒有,那么make就會往下面找,就會執行多條指令。
//makefile文件
test_9_10:test_9_10.ogcc -o test_9_10 test_9_10.o
test_9_10.o:test_9_10.sgcc -c test_9_10.s -o test_9_10.o
test_9_10.s:test_9_10.igcc -S test_9_10.i -o test_9_10.s
test_9_10.i:test_9_10.cgcc -E test_9_10.c -o test_9_10.i
.PHONY:clean
clean:rm -f test_9_10 *.i *.s *.o
[root@localhost d1]# ll
總用量 904
drwxr-xr-x. 3 root root 16 3月 13 15:32 d2
-rw-r--r--. 1 root root 278 9月 10 16:03 makefile
-rwxr-xr-x. 1 root root 8664 9月 10 11:13 test
-rw-r--r--. 1 root root 204 9月 10 15:27 test_9_10.c
-rw-r--r--. 1 root root 553 9月 10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月 10 11:13 test_static
[root@localhost d1]# make
gcc -E test_9_10.c -o test_9_10.i
gcc -S test_9_10.i -o test_9_10.s
gcc -c test_9_10.s -o test_9_10.o
gcc -o test_9_10 test_9_10.o
[root@localhost d1]# ll
總用量 944
drwxr-xr-x. 3 root root 16 3月 13 15:32 d2
-rw-r--r--. 1 root root 278 9月 10 16:03 makefile
-rwxr-xr-x. 1 root root 8664 9月 10 11:13 test
-rwxr-xr-x. 1 root root 8416 9月 10 16:03 test_9_10
-rw-r--r--. 1 root root 204 9月 10 15:27 test_9_10.c
-rw-r--r--. 1 root root 16921 9月 10 16:03 test_9_10.i
-rw-r--r--. 1 root root 1616 9月 10 16:03 test_9_10.o
-rw-r--r--. 1 root root 576 9月 10 16:03 test_9_10.s
-rw-r--r--. 1 root root 553 9月 10 14:19 test.c
-rwxr-xr-x. 1 root root 900440 9月 10 11:13 test_static
問題2:首先我們先了解“.PHONY”表示被修飾的目標是一個偽目標,偽目標總是要執行的。總是要執行就表示它不需要對比源文件和exe的修改時間,只要make它的指令就會可以一直執行。
[root@localhost d1]#stat test_9_10.c文件:"test_9_10.c"大小:204 塊:8 IO 塊:4096 普通文件
設備:fd00h/64768d Inode:33600218 硬鏈接:1
權限:(0644/-rw-r--r--) Uid:( 0/ root) Gid:( 0/ root)
環境:unconfined_u:object_r:home_root_t:s0
最近訪問:2025-09-10 15:31:25.887293504 +0800
最近更改:2025-09-10 15:27:21.934213096 +0800
最近改動:2025-09-10 15:27:21.936213031 +0800
創建時間:-
[root@localhost d1]# vim test_9_10.c
[root@localhost d1]# stat test_9_10.c文件:"test_9_10.c"大小:216 塊:8 IO 塊:4096 普通文件
設備:fd00h/64768d Inode:33600234 硬鏈接:1
權限:(0644/-rw-r--r--) Uid:( 0/ root) Gid:( 0/ root)
環境:unconfined_u:object_r:home_root_t:s0
最近訪問:2025-09-10 19:39:14.639976185 +0800
最近更改:2025-09-10 19:39:14.639976185 +0800
最近改動:2025-09-10 19:39:14.642975744 +0800
創建時間:-
//?件 = 內容 + 屬性
//Modify: 內容變更,時間更新(最近改動)
//Change:屬性變更,時間更新(最近更改)
//Access:常指的是?件最近?次被訪問的時間。在Linux的早期版本中,每當?件被訪問時,其
//atime都會更新。但這種機制會導致?量的IO操作。具體更新原則,不做過多解釋。
make執行第一條不是偽目標的指令時,會先比較文件的源文件是否在可執行文件的前后時間,來決定是否要重新編譯。如果源文件的修改時間比可執行文件晚,那么就不需要重新編譯,否則,需要。
語法擴展
BIN=proc.exe | 定義變量(類似于宏替換) |
SRC=$(shell ls *.c)? | 采?shell命令??式,獲取當前所有.c?件名 |
SRC=$(wildcard *.c) | 使? wildcard 函數,獲取當前所有.c?件名 |
OBJ=$(SRC:.c=.o) | 將SRC的所有同名.c 替換 成為.o 形成?標?件列表 |
LFLAGS=-o | 鏈接選項 |
FLAGS=-c | 編譯選項 |
RM=rm -f | 引?命令 |
$(BIN):$(OBJ) @$(CC) $(LFLAGS) $@ $^ | $@:代表?標?件名。 $^: 代表依賴?件列表 |
@$(CC) $(FLAGS) $< | %<: 對展開的依賴.c?件,?個?個的交給gcc。 |
@echo "compling ... $< to $@"? | @:不回顯命令,如果不加 @,終端會顯示:
然后再顯示:
加了
|
clean: $(RM) $(OBJ) $(BIN) # | $(RM): 替換,?變量內容替換它 |
%.o:%.c | %.c 展開當前?錄下所有的.c。 %.o: 同時展開同 名.o |
實例:
1 BIN=test_9_102 SRC=$(wildcard *.c)3 OBJ=$(SRC:.c=.o)4 LFLAGS=-o5 FLAGS=-c6 CC=gcc7 RM= rm -f8 $(BIN):$(OBJ)9 @$(CC) $(LFLAGS) $@ $^10 %.o:%.c11 @$(CC) $(FLAGS) $< 12 @echo "compling ...$< to $@"13 .PHONY:clean14 clean:15 $(RM) $(OBJ) $(BIN) //相當于rm -f *.o test_9_10
執行make指令:
[root@localhost d1]# make
compling ...test_9_10.c to test_9_10.o
[root@localhost d1]# ll
總用量 904
drwxr-xr-x. 3 root root 16 3月 13 15:32 d2
-rw-r--r--. 1 root root 228 9月 10 20:42 makefile
-rwxr-xr-x. 1 root root 8416 9月 10 20:35 test_9_10
-rw-r--r--. 1 root root 204 9月 10 20:35 test_9_10.c
-rw-r--r--. 1 root root 1616 9月 10 20:35 test_9_10.o
-rwxr-xr-x. 1 root root 900440 9月 10 11:13 test_static
[root@localhost d1]# make clean
rm -f test_9_10.o test_9_10
[root@localhost d1]# ll
總用量 888
drwxr-xr-x. 3 root root 16 3月 13 15:32 d2
-rw-r--r--. 1 root root 228 9月 10 20:42 makefile
-rw-r--r--. 1 root root 204 9月 10 20:35 test_9_10.c
-rwxr-xr-x. 1 root root 900440 9月 10 11:13 test_static
Linux第?個系統程序——進度條
預備知識
回車(\r)/換行(\n):
\r:把光標移到行首(不換行)
\n:把光標移到下一行
行緩沖區:
函數:fflush
#include<stdio.h>? ?int fflush(FILE*stream)//把用戶緩沖區的內容刷新到內核緩沖區中,并寫在文件stream中
比較下面三種結果有何不同:
1 #include<stdio.h>2 int main()3 {4 printf("hello world\n");5 sleep(3);6 return 0;7 }
現象:立馬打印“hello world”,然后光標在下一行閃爍三秒,然后打印命令條
1 #include<stdio.h>2 int main()3 {4 printf("hello world");5 sleep(3);6 return 0;7 }
現象:等待三秒后才打印“hello world”,然后在同一行上打印命令條
1 #include<stdio.h>2 int main()3 {4 printf("hello world");5 fflush(stdout);6 sleep(3);7 return 0;8 }
現象:立馬打印“hello world”,等待三秒后,然后在同一行上打印命令條
所以從上面的現象可以得出,
1.回車鍵和fflush函數可以進行行緩沖,把用戶緩沖區的內容刷新到內核緩沖區并刷新到輸出設備上。
2.程序結束也會自動刷新緩沖區。
練手——倒計時小程序
1 #include<stdio.h>2 int main()3 {4 int i=20;5 while(i--)6 {7 printf("%-2d\r",i);//保留兩位數字8 fflush(stdout);9 sleep(1);10 11 }12 printf("\n");13 return 0;14 }
進度條簡約版
//每秒加載1%1 #include<stdio.h>2 #include<string.h>3 int main()4 {5 char str[101]={0};6 int i=0;7 for(i=0;i<=100;i++)8 {9 printf("[%-100s] %d%%\r",str,i);10 str[i]='#';11 fflush(stdout);12 sleep(1);13 14 }15 printf("\n");16 17 return 0;18 }
我們常見的進度條都是會根據我們的網速來確定加載了多少,所以我們來實現一個進階版
進度條進階版
[root@localhost d1]# ./process
[####################################################################################################] ?[-] ?[100%]
download 1025.00MB Done
?
main.c
1 #include"process.h"2 double speed=1.0;3 double size=1024.0;4 void download()5 {6 7 double current=0;8 while(current<=size)9 {10 //打印進度條11 PrintfProcess(current,size);12 current+=speed;//注釋掉,可以觀察到進度一直在加載13 usleep(20000);14 }15 printf("\ndownload %.2lfMB Done\n",current);//current類型寫錯,輸出0.0016 }17 int main()18 {19 download();20 return 0;21 }
process.c
1 #include"process.h"2 void PrintfProcess(double current,double size)3 {4 char str[101];5 memset(str,0,sizeof(str));6 const char*lable="-\\|/";//“\\”轉義字符用來表示進度的加載效率7 int len=strlen(lable);8 int i=0;9 int num=(int)(current/size*100);10 for(i=0;i<num;i++)11 {12 str[i]='#';13 }14 static int cnt;15 cnt%=len;16 printf("[%-100s] [%c] [%.lf%%]\r",str,lable[cnt],current/size*100);17 cnt++;//即使卡頓了也一直在加載,檢測網絡在不在線18 fflush(stdout);19 }
lable字符串的作用:
process.h
1 #pragma once2 #include<stdio.h>3 #include<unistd.h>4 #include<string.h>5 void PrintfProcess(double current,double size);
makefile
1 SRC=$(wildcard *.c)2 OBJ=$(SRC:.c=.o)3 BIN=process4 $(BIN):$(OBJ)5 gcc -o $@ $^6 %.o:%.c7 gcc -c $<8 .PHONY:clean9 clean:10 rm -f $(OBJ) $(BIN)
調試器 - gdb/cgdb
樣例代碼:
// mycmd.c
#include <stdio.h>
int Sum(int s, int e)
{int result = 0;for(int i = s; i <= e; i++){result += i;}return result;
}
int main()
{int start = 1;int end = 100;printf("I will begin\n");int n = Sum(start, end);printf("running done, result is: [%d-%d]=%d\n", start, end, n);return 0;
}
預備知識點
1.程序有兩種發布方式,debug模式和release模式。Linux gcc/g++出來的二進制程序,默認時release模式。
2.debug模式才允許被調試,所以要使用gdb調試,必須在源代碼生成二進制程序的時候,加上-g選項,如果沒有添加,就不能進行調試。
[root@localhost d1]# gcc -o mycmd mycmd.c//默認模式,不支持調試
[root@localhost d1]# gdb mycmd
(gdb) l 1
No symbol table is loaded. ?Use the "file" command.
(gdb) quit
[root@localhost d1]# gcc -o mycmd mycmd.c -g//debug模式,支持調試
[root@localhost d1]# gdb mycmd
(gdb) l 1
5 ? ? ? int i;
常見命令
進入調試:gdb+可執行文件
退出調試:ctrl+d或q
命令 | 作? | 樣例 |
list/l | 顯示源代碼,從源文件中光標那行開始 | list/l 10 |
list/l 函數名 | 列出指定函數的源代碼 | list/l mian |
list/l 文件名:行號 | 列出指定文件的源代碼,如果只要指定的哪一行,那么就先設置 set listsize 1,就可以指定看哪一行,否則都是從第一行開始展示 | list/l mycmd.c:1 |
r/run | 從程序開始連續執行 | run |
n/next | 單步執行,不進入函數內部,相當于逐過程F10 | next |
s/step | 單步執行,進入函數內部,相當于逐語句F11 | |
break/b? | 在指定行號設置斷點 | b 10 break mycmd.c 10 |
break/b 函數名 | 在函數開頭設置斷點 | break main |
info break/b | 查看所有斷點信息 | info break |
finish | 執行到當前函數的返回,然后停止 | |
print/p 表達式 | 打印表達式的值 | print end+start |
?p 變量 | 打印指定變量的值 | p x |
set var 變量=值 | 修改變量的值 | set var i=10 |
continue/c | 從當前位置開始連續執行程序 | continue |
delete/d breakpoints | 刪除所有斷點 | |
delete/d breakpoints n | 刪除序號為n的斷點 | delete/d breakpoints 1 |
disable breakpoints | 禁用所有斷點 | |
enable breakpoints | 啟用所有斷點 | |
display 變量名 | 跟蹤顯示指定變量的值(每次停止時) | display x |
undisplay 編號 | 取消對指定編號的變量的跟蹤顯示 | undisplay 1 |
until x行號 | 執行到指定行號 | until 10 |
backtrace/bt | 查看當前執行棧的各級函數調用及參數 | |
info/i locals | 查看當前棧幀的局部變量值 | |
quit/q | 退出gdb調試器 |
注:n、s、finish、c、display/undisplay、until都必須在執行期間才可以使用。
watch
執行時監視?個表達式(如變量)的值。如果監視的表達式在程序運行期間的值發生變化,GDB 會暫停程序的執行,并通知使用者。
(gdb) l main
8 result += i;
9 }
10 return result;
11 }
12 int main()
13 {
14 int start = 1;
15 int end = 100;
16 printf("I will begin\n");
17 int n = Sum(start, end);
(gdb) b 17
Breakpoint 1 at 0x4005cd: file mycmd.c, line 17.
(gdb) r
Starting program: /home/d1/mycmd
I will beginBreakpoint 1, main () at mycmd.c:17
17 int n = Sum(start, end);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.3.x86_64
(gdb) s
Sum (s=1, e=100) at mycmd.c:4
4 int result = 0;
(gdb) n
6 for(i = s; i <= e; i++)
(gdb) watch result
Hardware watchpoint 2: result
(gdb) c
Continuing.
Hardware watchpoint 2: resultOld value = 0
New value = 1
Sum (s=1, e=100) at mycmd.c:6
6 for(i = s; i <= e; i++)
(gdb) c
Continuing.
Hardware watchpoint 2: resultOld value = 1
New value = 3
Sum (s=1, e=100) at mycmd.c:6
6 for(i = s; i <= e; i++)
注:如果你有一些變量不應該修改,但是你懷疑它修改導致了問題,你可以watch它,如
果變化了,就會通知。
條件斷點
實際上就是在設置斷點的時候給斷點加個條件,當運行起來后finish就會停在設置條件的那個位置。比如 b 8?if i==30,那么程序就會在第八行且i=30的時候停止執行。可以驗證中間部分是否結果錯誤。
新建條件斷點
(gdb) l Sum
1 #include <stdio.h>
2 int Sum(int s, int e)
3 {
4 int result = 0;
5 int i;
6 for(i = s; i <= e; i++)
7 {
8 result += i;
9 }
10 return result;
(gdb) l main
8 result += i;
9 }
10 return result;
11 }
12 int main()
13 {
14 int start = 1;
15 int end = 100;
16 printf("I will begin\n");
17 int n = Sum(start, end);
(gdb) b 17
Breakpoint 1 at 0x4005cd: file mycmd.c, line 17.
(gdb) r
Starting program: /home/d1/mycmd
I will beginBreakpoint 1, main () at mycmd.c:17
17 int n = Sum(start, end);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.3.x86_64
(gdb) s
Sum (s=1, e=100) at mycmd.c:4
4 int result = 0;
(gdb) s
6 for(i = s; i <= e; i++)
(gdb) n
8 result += i;
(gdb) n
6 for(i = s; i <= e; i++)
(gdb) n
8 result += i;
(gdb) b 8 if i==30
Breakpoint 2 at 0x400596: file mycmd.c, line 8.
(gdb) display i
1: i = 2
(gdb) finish
Run till exit from #0 Sum (s=1, e=100) at mycmd.c:8Breakpoint 2, Sum (s=1, e=100) at mycmd.c:8
8 result += i;
1: i = 30
(gdb) p result//可以查看result的值
$1 = 435
在新增斷點上設置條件
(gdb) b 17
Breakpoint 1 at 0x4005cd: file mycmd.c, line 17.
(gdb) r
Starting program: /home/d1/mycmd?
I will beginBreakpoint 1, main () at mycmd.c:17
17?? ??? ?int n = Sum(start, end);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.3.x86_64
(gdb) s
Sum (s=1, e=100) at mycmd.c:4
4?? ??? ? int result = 0;
(gdb) s
6?? ??? ? for(i = s; i <= e; i++)
(gdb) n
8?? ??? ??? ??? ? result += i;
(gdb) n
6?? ??? ? for(i = s; i <= e; i++)
(gdb) n
8?? ??? ??? ??? ? result += i;
(gdb) n
6?? ??? ? for(i = s; i <= e; i++)
(gdb) n
8?? ??? ??? ??? ? result += i;
(gdb) b
Breakpoint 2 at 0x400596: file mycmd.c, line 8.
(gdb) info b
Num ? ? Type ? ? ? ? ? Disp Enb Address ? ? ? ? ? ?What
1 ? ? ? breakpoint ? ? keep y ? 0x00000000004005cd in main at mycmd.c:17
?? ?breakpoint already hit 1 time
2 ? ? ? breakpoint ? ? keep y ? 0x0000000000400596 in Sum at mycmd.c:8
(gdb) condition 2 i==30 //不需要if
(gdb) info b
Num ? ? Type ? ? ? ? ? Disp Enb Address ? ? ? ? ? ?What
1 ? ? ? breakpoint ? ? keep y ? 0x00000000004005cd in main at mycmd.c:17
?? ?breakpoint already hit 1 time
2 ? ? ? breakpoint ? ? keep y ? 0x0000000000400596 in Sum at mycmd.c:8
?? ?stop only if i==30
?? ?breakpoint already hit 2 times
(gdb) n
6?? ??? ? for(i = s; i <= e; i++)
(gdb) n
8?? ??? ??? ??? ? result += i;
(gdb) c
Continuing.Breakpoint 2, Sum (s=1, e=100) at mycmd.c:8
8?? ??? ??? ??? ? result += i;
(gdb) p i
$2 = 30
(gdb) p result
$3 = 435
注:Ctrl+X松開后按a就可以進入GDB TUI(Text User Interface)模式 下的分屏操作,按Esc可以切換到源代碼區域,可以按上下鍵實現翻頁;按i鍵可以切換回gdb模式。