Linux 系统编程
- Linux 系统编程(文章链接汇总)
$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh # 已经被 /bin/bash 所取代
/bin/bash # Linux 默认的 shell
/bin/rbash
/bin/dash
$ echo $SHELL
/bin/bash
$ history
# 按下 Ctrl+r 后,输入关键字 'sq'
$ (reverse-i-search)`sq': sqlite3
/:根目录
/bin:
bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令
/boot:
这里存放的是启动 Linux 时使用的一些核心文件,包括一些连接文件以及镜像文件
/dev :
dev 是 Device(设备) 的缩写, 该目录下存放的是 Linux 的外部设备,在 Linux 中访问设备的方式和访问文件的方式是相同的
/etc:
etc 是 Etcetera(等等) 的缩写,这个目录用来存放所有的系统管理所需要的配置文件和子目录
/home:
用户的主目录,在 Linux 中,每个用户都有一个自己的目录,一般该目录名是以用户的账号命名的,如上图中的 alice、bob 和 eve
/lib:
lib 是 Library(库) 的缩写这个目录里存放着系统最基本的动态连接共享库,其作用类似于 Windows 里的 DLL 文件。几乎所有的应用程序都需要用到这些共享库
/media:
linux 系统会自动识别一些设备,例如U盘、光驱等等,当识别后,Linux 会把识别的设备挂载到这个目录下
/mnt:
系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将光驱挂载在 /mnt/ 上,然后进入该目录就可以查看光驱里的内容了
/opt:
opt 是 optional(可选) 的缩写,这是给主机额外安装软件所摆放的目录。比如你安装一个ORACLE数据库则就可以放到这个目录下。默认是空的
/proc:
proc 是 Processes(进程) 的缩写,/proc 是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息
/root:
该目录为系统管理员,也称作超级权限者的用户主目录
/sbin:
s 就是 Super User 的意思,是 Superuser Binaries (超级用户的二进制文件) 的缩写,这里存放的是系统管理员使用的系统管理程序
/selinux:
这个目录是 Redhat/CentOS 所特有的目录,Selinux 是一个安全机制,类似于 windows 的防火墙,但是这套机制比较复杂,这个目录就是存放selinux相关的文件的
/srv:
该目录存放一些服务启动之后需要提取的数据
/sys:
这是 Linux2.6 内核的一个很大的变化。该目录下安装了 2.6 内核中新出现的一个文件系统 sysfs
/tmp:
tmp 是 temporary(临时) 的缩写这个目录是用来存放一些临时文件的
/usr:
usr 是 unix shared resources(共享资源) 的缩写,这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于 windows 下的 program files 目录
/usr/bin:
系统用户使用的应用程序
/usr/sbin:
超级用户使用的比较高级的管理程序和系统守护程序
/usr/src:
内核源代码默认的放置目录
/var:
var 是 variable(变量) 的缩写,这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件
/run:
是一个临时文件系统,存储系统启动以来的信息。当系统重启时,这个目录下的文件应该被删掉或清除。如果你的系统上有 /var/run 目录,应该让它指向 run
位于 /home/user,称之为用户工作目录或家目录,两种表示方式如下
$ /home/user
$ ~
yxd@yxd-VirtualBox:~$ cd /home/
yxd@yxd-VirtualBox:/home$ cd ~
yxd@yxd-VirtualBox:~$
相对、绝对路径
# 绝对路径:从/目录开始描述的路径为绝对路径
$ cd /home/
# 从当前位置开始描述的路径为相对路径
$ cd ../../
每个目录下都有 . 和 …
-a 列出隐藏文件,文件中以 “.” 开头的均为隐藏文件,如:~/.bashrc
-l 列出文件的详细信息
-R 连同子目录中的内容一起列出
$ ls -l
total 236
-rw-r--r-- 1 yxd yxd 0 11月 14 19:05 apitest
drwxrwxr-x 2 yxd yxd 4096 7月 31 13:41 bag
...
...
-rw-r--r-- 1 yxd yxd 0 11月 13 19:46 my,db
-rw-r--r-- 1 yxd yxd 24576 11月 14 15:40 my.db
lrwxrwxrwx 1 yxd yxd 13 9月 14 15:37 myfile -> /no/such/file
- 普通文件
d 目录
l 符号链接
b 块设备文件
c 字符设备文件
s socket文件,网络套接字
p 管道
r 读
w 写
x 可执行。对于目录,表示进入权限
s 当文件被执行时,把该文件的 UID 或 GID 赋予执行进程的 UID(用户 ID)或 GID(组 ID)
t 设置标志位(sticky bit)。如果有 sticky bit 的目录,在该目录下任何用户只要有适当的权限即可创建文
件,但文件只能被超级用户、目录拥有者或文件属主删除。如果是有sticky bit的可执行文件,在该文件执行后,
指向其正文段的指针仍留在内存。这样再次执行它时,系统就能更快地装入该文件。
- 没有相应位置的权限
访问权限后面的数字表示与该文件共享 inode 的文件总数,即硬链接数
$ cd ~ # 直接输入 cd 也能直接进入 ~ 目录下
$ cd dir1/dir2
$ cd ..
$ which ls
$ pwd
$ mkdir a
$ mkdir a/b
$ ls a
b
$ rmdir a/b
$ ls a
$ rmdir a
# 后面跟着 -p,表示可以连同父目录一起创建
$ mkdir -p a/b
$ ls a
b
# 后面跟着 -p,表示可以连同空的父目录一起删除
$ rmdir -p a/b
# 删除文件
$ rm file
# 删除目录
$ rm -rf dir
# 重命名
$ mv file1 file2
# 移动文件
$ mv file1 ~/
# 拷贝文件
$ cp file1 file2
$ cp file1 dir/
$ cp file1 ../
# 拷贝目录
cp -r dir1 dir2
cp -r dir1 ~/
# 显示文件 file1 的前 5 行
$ head -5 file1
# 显示文件 file1 的后 5 行
$ tail -5 file1
# 硬链接
$ touch hello
$ ln hello word_h
# 软链接
$ ln -s hello word_s
# 使用该命令前需进行安装
$ sudo apt-get install tree
$ wc -l ./*
# -c 或 –bytes 或 –chars 只显示 Bytes 数
# -l 或 –lines 只显示列数
# -w 或 –words 只显示字数
$ od -tcx file1 # 显示格式:ASCII 字符/反斜杠序列 + 十六进制数
# -t 后的主要参数有
# c ASCII 字符或反斜杠序列
# d[SIZE] 有符号十进制数,每个整数 SIZE 字节
# f[SIZE] 浮点数,每个整数 SIZE 字节
# o[SIZE] 八进制(系统默认值为 02),每个整数 SIZE 字节
# u[SIZE] 无符号十进制数,每个整数 SIZE 字节
# x[SIZE] 十六进制数,每个整数 SIZE 字节
$ df --block-size=GB
$ df --block-size=MB
# 以 M 为单位
$ du -hm /home/itcast/test
# 以 B 为单位
$ du -hb ./*
# 以K为单位,4k 的整数倍
$ du -hk ./*
# 总计大小,以 M 为单位
$ du -hc ./*
$ chmod [who] [+|-|=] [mode] 文件名
u 表示 “用户(user)”,即文件或目录的所有者
g 表示 “同组(group)用户”,即与文件属主有相同组 ID 的所有用户
o 表示 “其他(others)用户”
a 表示 “所有(all)用户”,它是系统默认值
+ 添加某个权限
- 取消某个权限
= 赋予给定权限并取消其他所有权限(如果有的话)
r 可读
w 可写
x 可执行
$ chmod [mode] 文件名
# 0 表示没有权限
# 1 表示可执行权限
# 2 表示可写权限
# 4 表示可读权限
# 设置一个文件允许所有用户可读、可写、可执行
$ chmod 777 file1
user group other
r w x r w x r w x
4 2 1 4 2 1 4 2 1
7 7 7
chown [OPTION]… [OWNER:GROUP] FILE…
chown [OPTION]… –reference=RFILE FILE…
$ sudo chown itcast:nogroup file1
chgrp [OPTION]… GROUP FILE…
chgrp [OPTION]… –reference=RFILE FILE…
$ find pathname -options [-print -exec -ok -name -type...]
$ find . -name 'file*' # 在当前目录及子目录下查找所有以 file 开头的文件名
$ find / -name 'vimrc'
$ find ~ -name '*.c'
$ find /usr/ -name "*tmp*" -exec ls -l { } \;
$ find ./ -name "*tmp" -ok rm { } \;
-I:不区分大小写(只适用于单字符)
-h:查询多文件时不显示文件名
-l:查询多文件时只输出包含匹配字符的文件名
-n:显示匹配行及行号
-s:不显示不存在或无匹配文本的错误信息
-v:显示不包含匹配文本的所有行
-R:连同子目录中所有文件一起查找
$ grep 'printf' /usr/include -R
$ sudo vi /etc/apt/sources.list
$ sudo apt-get update # 更新源
$ sudo apt-get install package # 安装包
$ sudo apt-get remove package # 删除包
$ sudo apt-cache search package # 搜索软件包
$ sudo apt-cache show package # 获取包的相关信息,如说明、大小、版本等
$ sudo apt-get install package --reinstall # 重新安装包
$ sudo apt-get -f install # 修复安装
$ sudo apt-get remove package --purge # 删除包,包括配置文件等
$ sudo apt-get build-dep package # 安装相关的编译环境
$ sudo apt-get upgrade # 更新已安装的包
$ sudo apt-get dist-upgrade # 升级系统
$ sudo apt-cache depends package # 了解使用该包依赖那些包
$ sudo apt-cache rdepends package # 查看该包被哪些包依赖
$ sudo apt-get source package # 下载该包的源代码
$ sudo apt-get clean && sudo apt-get autoclean # 清理无用的包
$ sudo apt-get check # 检查是否有损坏的依赖
$ sudo dpkg -i xxx.deb # 安装 deb 软件包命令
$ sudo dpkg -r xxx.deb # 删除软件包命令
$ sudo dpkg -r --purge xxx.deb # 连同配置文件一起删除命令
$ sudo dpkg -info xxx.deb # 查看软件包信息命令
$ sudo dpkg -L xxx.deb # 查看文件拷贝详情命令
$ sudo dpkg -l # 查看系统中已安装软件包信息命令
$ sudo dpkg-reconfigure xxx # 重新配置软件包命令
$ cd dir
$ ./configure # 检测文件是否缺失,创建 Makefile,检测编译环境
$ make # 编译源码,生成库和可执行程序
$ sudo make install # 把库和可执行程序,安装到系统路径下
$ sudo make distclean # 删除和卸载软件
# 打包
# c 创建新的档案文件
# x 从档案文件中释放文件
# v 详细报告 tar 处理的文件信息
# f 使用档案文件或设备
$ tar cvf dir.tar dir
$ tar xvf dir.tar dir
# 打 gz 压缩包
# z 用 gzip 来压缩/解压缩文件,加上该选项后可以将档案文件进行压缩,但还原时也一定要使用该选项进行解压缩
$ tar zcvf dir.tar.gz dir
$ tar zxvf dir.tar.gz
# 打 bz2 压缩包
# j 用 bzip2 来压缩/解压缩文件,加上该选项后可以将档案文件进行压缩,但还原时也一定要使用该选项进行解压缩
$ tar jcvf dir.tar.bz2 dir
$ tar jxvf dir.tar.bz2
# 指定目录解压缩
$ tar zxvf dir.tar.gz -C ~/test
# 打包:把 dir 压缩成 newdir.rar
$ rar a -r newdir dir
# 解包:把 newdir.rar 解压缩到当前目录
$ unrar x newdir.rar
# 打包:把 dir 压缩成 dir.zip
$ zip -r dir.zip dir
# 解包
$ unzip dir.zip
$ who
yxd :0 2023-12-08 14:40 (:0)
-e:显示所有进程
-f:全格式
-h:不显示标题
-l:长格式
-w:宽输出
-r:只显示正在运行的进程
-a:即 all,表示显示所有用户的进程,即包括其他用户的进程
-u:表示以用户为主的格式来显示进程信息,包括进程的用户、进程 ID、CPU 占用率、内存占用率等
-j:表示输出进程的详细信息,包括进程所属用户、进程 ID、父进程 ID、CPU 占用率、内存占用率等
-x:表示显示无选项进程,即显示不属于当前终端的进程
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 225612 9436 ? Ss 14:39 0:01 /sbin/in
root 2 0.0 0.0 0 0 ? S 14:39 0:00 [kthread
root 3 0.0 0.0 0 0 ? I< 14:39 0:00 [rcu_gp]
...
...
$ ps ajx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 0:01 /sbin/init splash
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 3 0 0 ? -1 I< 0 0:00 [rcu_gp]
...
...
# Head 标头含义解析
USER 用户名
UID 用户 ID(User ID)
PID 进程 ID(Process ID)
PPID 父进程的进程 ID(Parent Process id)
SID 会话 ID(Session id)
%CPU 进程的 CPU 占用率
%MEM 进程的内存占用率
VSZ 进程所使用的虚存的大小(Virtual Size)
RSS 进程使用的驻留集大小或者是实际内存的大小,Kbytes 字节
TTY 与进程关联的终端(tty)
STAT 进程的状态:进程状态使用字符表示的(STAT 的状态码)
R 运行 Runnable (on run queue) 正在运行或在运行队列中等待
S 睡眠 Sleeping 休眠中, 受阻, 在等待某个条件的形成或接受到信号
I 空闲 Idle
Z 僵死 Zombie(a defunct process) 进程已终止, 但进程描述符存在, 直到父进程调用 wait4() 系统调
用后释放
D 不可中断 Uninterruptible sleep(ususally IO) 收到信号不唤醒和不可运行, 进程必须等待直到有中
断发生
T 停止 Terminate 进程收到 SIGSTOP, SIGSTP, SIGTIN, SIGTOU 信号后停止运行运行
P 等待交换页
W 无驻留页 has no resident pages 没有足够的记忆体分页可分配
X 死掉的进程
< 高优先级进程高优先序的进程
N 低优先级进程低优先序的进程
L 内存锁页 Lock 有记忆体分页分配并缩在记忆体内
s 进程的领导者(在它之下有子进程)
l 多进程的(使用CLONE_THREAD, 类似NPTL pthreads)
+ 位于后台的进程组
START 进程启动时间和日期
TIME 进程使用的总 CPU 时间
COMMAND 正在执行的命令行命令
NI 优先级 (Nice)
PRI 进程优先级编号 (Priority)
WCHAN 进程正在睡眠的内核函数名称;该函数的名称是从 /root/system.map 文件中获得的
FLAGS 与进程相关的数字标识
$ cat
^Z # 按下Ctrl-z挂起当前进程
[1]+ Stopped cat
$ cat
^Z
[2]+ Stopped cat
$ jobs
[1]- Stopped cat
[2]+ Stopped cat
# 第一列中的数字表示作业序号,由当前运行的 shell 分配
# 第二列中的 “+” 号表示相应作业的优先级比 “-” 号对应作业的优先级高
# 第三列表明作业状态,是否为运行、中断、等待输入或停止等
# 第四列是创建当前这个作业所对应的命令行
$ kill [ -signal | -s signal ] pid ...
$ kill -l [ signal ]
$ cat
$ # 按 ctrl+z 挂起当前进程
[1]+ Stopped cat
$ ps
PID TTY TIME CMD
5819 pts/1 00:00:00 bash
5893 pts/1 00:00:00 cat
5894 pts/1 00:00:00 ps
$ kill -SIGKILL 5893 # 被挂起的进程不能处理信号,必须发 SIGKILL 信号,由系统强制终止进程
$ # 再次按回车键
[1]+ Killed cat
$
$ env
$ vim ~/.bashrc
$ vim /etc/profile
$ export PATH=$PATH:新路径
# 查看网卡信息
$ ifconfig
# 关闭网卡
$ sudo ifconfig eth0 down
# 开启网卡 eth0
$ sudo ifconfig eth0 up
# 给 eth0 配置临时 IP
$ sudo ifconfig eth0 IP
$ ping [选项] 主机名/IP地址
$ netstat [选项]
$ nslookup name
# 安装 ssh 服务器
$ sudo apt-get install openssh-server
# 远程登陆
$ ssh 用户名@IP
$ poweroff
$ reboot
$ shutdown -r now 立刻重新开机
$ shutdown -h now 立刻关机
$ man man
$ man read # 查看 read 命令的 man page
$ man 2 read # 查看 read 系统函数的 man page(在第二个 section 中,表示为 read(2))
$ man -k read # 以 read 为关键字查找相关的 man page
# 快捷键 ctrl+l
$ clear
$ echo [-n] 字符串
创建终端标签 Ctrl + Shift + t
切换标签 Alt+n(n=1)
新开终端 Ctrl + Shift + n
i: 插入光标前一个字符
I: 插入行首
a: 插入光标后一个字符
A: 插入行未
o: 向下新开一行,插入行首
O: 向上新开一行,插入行首
h: 左移
j: 下移
k: 上移
l: 右移
M: 光标移动到中间行
L: 光标移动到屏幕最后一行行首
G: 移动到指定行,行号 -G
w: 向后一次移动一个字
b: 向前一次移动一个字
{: 按段移动,上移
}: 按段移动,下移
Ctr-d: 向下翻半屏
Ctr-u: 向上翻半屏
Ctr-f: 向下翻一屏
Ctr-b: 向上翻一屏
gg: 光标移动文件开头
G: 光标移动到文件末尾
x: 删除光标后一个字符,相当于 Del
X: 删除光标前一个字符,相当于 Backspace
dd: 删除光标所在行,n dd 删除指定的行数 D: 删除光标后本行所有内容,包含光标所在字符
d0: 删除光标前本行所有内容,不包含光标所在字符
dw: 删除光标开始位置的字,包含光标所在字符
u: 一步一步撤销
Ctr-r: 反撤销
.: 重复上一次操作的命令
yy: 复制当前行,n yy 复制 n 行
p: 在光标所在位置向下新开辟一行,粘贴
v: 按字符移动,选中文本
V: 按行移动,选中文本可视模式可以配合 d, y, >>, << 实现对文本块的删除,复制,左右移动
r: 替换当前字符
R: 替换当前行光标后的字符
/: str 查找
n: 下一个
N:上一个
K:在系统函数上按 K 直接跳转到 man page
#:在自定义函数上按 # 直接跳转到函数定义
末行模式下,将光标所在行的 abc 替换成 123
:%s/abc/123/g
末行模式下,将第一行至第 10 行之间的 abc 替换成 123
:1,10s/abc/123/g
光标移动到函数上,Shift-k 光标移动到函数上
3Shift-k,查看第三章的 ManPage
gg=G
末行模式里输入!,后面跟命令
sp:上下分屏,后可跟文件名
vsp:左右分屏,后可跟文件名
Ctrl+w+w:在多个窗口切换
# 使用大写 O 参数进行垂直分屏
# n 是数字,表示分屏的数量,n 要大于等于文件个数
$ vim -On file1 file2 ...
# 使用小写 o 参数进行水平分屏
$ vim -on file1 file2 ...
# 关闭当前窗口
$ ctrl+w c
# 关闭当前窗口,如果只剩最后一个,则退出vim
$ ctrl+w q
-v –version 查看 gcc 版本号
-I 目录 指定头文件目录,注意 -I 和目录之间空格可有可无
-c 只做预处理、编译、汇编,得到 .o 二进制文件,不进行链接
-g 编译时添加调试文件,用于 gdb 调试
-On n=0∼3 编译优化,n 越大优化得越多(嵌入式编程中使用较多,默认 n = 2)
-Wall 显示所有警告信息
-D 编译时定义宏,注意 -D 和 之间没有空格
-E 生成预处理文件
-M 生成 .c 文件与头文件依赖关系以用于 Makefile,包括系统库的头文件
-MM 生成 .c 文件与头文件依赖关系以用于 Makefile,不包括系统库的头文件
$ vi hello.c
$ gcc hello.c -o hello
$ ls
hello hello.c hello.h
$ ./hello
-----------
$ mkdir include
$ mv hello.h include/
$ ls
hello hello.c include
$ gcc hello.c -o hello
hello.c:1:10: fatal error: hello.h: No such file or directory
#include "hello.h"
^~~~~~~~~
compilation terminated.
# 当头文件和源码不在一个目录下时,需要使用 -I 参数指定头文件所在位置
$ gcc -I./include hello.c -o hello
$ ls
hello hello.c include
$ ./hello
-----------
# 1. 将 .c 生成 .o 文件
$ gcc -c add.c -o add.o
$ gcc -c sub.c -o sub.o
$ gcc -c div1.c -o div1.o
$ ls
add.c add.o div1.c div1.o sub.c sub.o
# 2. 使用 ar 工具制作静态库
$ ar rcs libmymath.a add.o sub.o div1.o
$ ls
add.c add.o div1.c div1.o libmymath.a sub.c sub.o
# 3. 编译静态库到可执行文件中
$ gcc test.c libmymath.a -o test
# 当存在头文件且在 include 目录下,静态库文件在 lib 目录下时
$ gcc test.c ./lib/libmymath.a -o test -I ./include
# 1. 将 .c 生成 .o 文件(生成与位置无关的代码 -fPIC)
$ gcc -c add.c -o add.o -fPIC
$ gcc -c sub.c -o sub.o -fPIC
$ gcc -c div1.c -o div1.o -fPIC
$ ls
add.c add.o div1.c div1.o sub.c sub.o
# 2. 使用 gcc -shared 制作动态库
$ gcc -shared -o libmymath.so add.o sub.o div1.o
$ ls
add.c add.o div1.c div1.o libmymath.so sub.c sub.o
# 3. 编译可执行程序时指定所使用的动态库。-l:指定库名 -L:指定库路径
# 链接器:工作于链接阶段,工作时需要 -l 和 -L
# 此处 -l 后的库名需要去掉前缀 lib- 和后缀 .so
$ gcc test.c -o test -l mymath -L ./lib
# 当存在头文件且在 include 目录下,静态库文件在 lib 目录下时
$ gcc test.c -o test -l mymath -L ./lib -I ./include
# 4. 动态链接器:工作于程序运行阶段,工作时需要提供动态库所在目录位置
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib # 临时生效,终端重启后环境变量失效
$ vi ~/.bashrc # 永久生效,将 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib 写入 .bashrc,建议使用绝对路径
$ source .bashrc
$ mkdir mycal
// add.c
int add(int a, int b) {
return a+b;
}
// sub.c
int add(int a, int b) {
return a-b;
}
// mul.c
int add(int a, int b) {
return a*b;
}
// dive.c
int add(int a, int b) {
return a/b;
}
// common.h
#ifndef COMMON_H_
#define COMMON_H_
int add(int a, int b);
int sub(int a, int b);
int dive(int a, int b);
int mul(int a, int b);
#endif
$ gcc -c add.c sub.c mul.c dive.c
$ ar rcs libmycal.a add.o sub.o mul.o dive.o
$ gcc -c add.c sub.c mul.c dive.c -fPIC
$ gcc -shared -Wl, -soname, libmycal.so.1 -o libmycal.so.1.10 add.o sub.o mul.o dive.o
$ sudo vi /etc/ld.so.conf
# 最后一行添加 mycal 路径
/home/yue-VirtualBox/mycal
$ sudo ldconfig -v
$ ln -s libmycal.so.1.10 libmycal.so
// main.c
#include
#include "common.h"
int main(void) {
printf("%d\n", add(5, 3));
return 0;
}
list/l:列出源码,根据源码指定行号设置断点
break/b:b 20 在 20 行位置设置断点
run/r:全速运行程序
start:单步运行程序
next/n:下一条指令(会越过函数)
step/s:下一条指令(会进入函数)
print/p:p i 查看变量的值
delete/d:删除断点
continue/c:继续执行断点后续指令(剩下代码)
finish:结束当前函数调用
quit:退出 gdb 当前调试
run:使用 run 查找段错误出现位置
set args:设置 main 函数命令行参数(在 start、run 之前)
run argv[1] argv[2]:设置 main 函数命令行参数(调试时命令行传参)
info b:查看断点信息表
b 20 if i = 5:设置条件断点
ptype:查看变量类型
backtrace/bt:查看函数的调用的栈帧和层级关系
frame:根据栈帧编号,切换栈帧
display:设置跟踪变量
undisplay:取消设置跟踪变量,使用跟踪变量的编号
栈帧:随着函数调用而在 stack 上开辟的一片内存空间,用于存放函数调用时产生的局部变量和临时值,随函数调用结束而自动释放内存空间
// gdbtest.c
#include
#include
#include
#define N 10
char *str = "hello ";
int var = 0;
void init_arr(int *arr, int len) {
int i = 0;
for (i = 0; i < len; i++) {
arr[i] = rand() % 20 + 1;
}
}
void select_sort(int *arr, int len) {
int i, j, k, tmp;
for (i = 0; i < len - 1; i++) {
k = i;
for (j = i + 1; j < len; j++) {
if (arr[k] > arr[j]) {
k = j;
}
}
if (i != k) {
tmp = arr[i];
arr[i] = arr[k];
arr[k] = tmp;
}
}
}
void print_arr(int *arr, int len) {
int i;
for (i = 0; i < len; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
}
int main(void) {
int arr[N];
char *p = "hello";
srand(time(NULL));
init_arr(arr, N);
print_arr(arr, N);
//p[3] = 'M';
select_sort(arr, N);
printf("------after sort------\n");
print_arr(arr, N);
return 0;
}
$ gcc gdbtest.c -o gdbtest -g
$ gdb gdbtest
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later //gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
//www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
//www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from gdbtest...done.
(gdb) list 1
1 #include
2 #include
3 #include
4
5 #define N 10
6
7 char *str = "hello ";
8 int var = 0;
9
10 void init_arr(int *arr, int len) {
(gdb) l
11 int i = 0;
12
13 for (i = 0; i < len; i++) {
14 arr[i] = rand() % 20 + 1;
15 }
16 }
17
18 void select_sort(int *arr, int len) {
19 int i, j, k, tmp;
20
(gdb) b 50
Breakpoint 1 at 0x9b6: file gdbtest.c, line 50.
(gdb) r
Starting program: /home/yue/gdbtest
Breakpoint 1, main () at gdbtest.c:50
50 init_arr(arr, N);
s
init_arr (arr=0x7fffffffdae0, len=10) at gdbtest.c:11
11 int i = 0;
(gdb) n
13 for (i = 0; i < len; i++) {
(gdb) s
14 arr[i] = rand() % 20 + 1;
(gdb) n
13 for (i = 0; i < len; i++) {
(gdb) p i
$1 = 0
(gdb) continue
Continuing.
arr[0] = 5
arr[1] = 13
arr[2] = 3
arr[3] = 12
arr[4] = 17
arr[5] = 19
arr[6] = 7
arr[7] = 15
arr[8] = 8
arr[9] = 16
------after sort------
arr[0] = 3
arr[1] = 5
arr[2] = 7
arr[3] = 8
arr[4] = 12
arr[5] = 13
arr[6] = 15
arr[7] = 16
arr[8] = 17
arr[9] = 19
[Inferior 1 (process 3214) exited normally]
(gdb) run # 增加该行代码后 p[3] = 'M'; 出现段错误,直接使用 run 调试会跳转到段错误所在行
Starting program: /home/yue/gdbtest
arr[0] = 10
arr[1] = 14
arr[2] = 2
arr[3] = 18
arr[4] = 10
arr[5] = 3
arr[6] = 18
arr[7] = 19
arr[8] = 16
arr[9] = 11
Program received signal SIGSEGV, Segmentation fault.
0x00005555555549e0 in main () at gdbtest.c:52
52 p[3] = 'M';