目录
前言
希望您在基本了解了Linux的常用指令和权限等基本问题后再阅读本篇博客。
我们在使用Windows操作系统或手机的安卓系统的时候总不可能一直使用系统默认的一些软件工具吧?我们可能希望增加一些我word、excel和ppt等一些基础的开发工具,随着使用的熟练我们还可能需要一些诸如ps、devC++和python等更高能的开发工具,甚至我们会下载安装一些游戏来丰富我们的网络生活。那么接下来我们就来了解一下Linux的基础开发工具,以及如何使用它们
一、yum —— 软件包管理工具
1.1 yum的简介
在Linux下安装软件, 一个通常的办法是下载程序的源代码,并进行编译,得到可执行程序。但是这样太麻烦了(源代码本身可能存在bug,编译源代码对目前的处于学习阶段的我们来说难度非常大,而且可能程序本身依赖于某些其它程序或第三方库),于是有些人把一些常用的软件提前编译好,做成软件包(可以理解成windows上的安装程序)放在一个服务器上,通过软件包管理器可以很方便的获取到这个编译好的软件包,直接进行安装(安装的本质就是把可执行程序拷贝到指定的路径下)。有的读者可能马上就想到了,这不就和我们手机上的什么应用商店之类的软件一样吗?事实如此,软件包和软件包管理器,就好比 "App" 和 "应用商店" 之间的关系。
yum(Yellow dog Updater,Modified)是Linux下非常常用的一种包管理器。主要应用在Fedora, RedHat,Centos等发行版上。我们可以通过下面这张图大致了解一下yum和yum的生态
然而,由于Linux服务器是由老外搭建的,里面大部分的资源也是由老外提供分享的,我们想要直接获取这些资源可能并不是那么轻松(?涉及网络安全问题)。因此,国内也提供了一些镜像源,一般情况下,我们使用yum指令是从国内的镜像源获取的软件包链接。1.2 yum的使用
下面我们可以实际操作一下,通过yum下载一些有趣的软件指令
安装软件需要较高的权限,可以通过sudo或切换到root账号执行命令 安装指令:yum install -y sl 卸载指令:yum remove sl sl #此命令可以在屏幕上驶过一辆小火车 sl -c #显示有故障的小火车 sl -F #小火车驶过的过程中缓缓上升 读者可以自行搜索更多有趣的指令... 如果发现这些指令无法执行,可以先安装一个yum源插件 yum install -y epel-release
如图,如果你不小心把"ls"指令写成了"sl",那么一辆小火车就会打断你的工作
" yum list "命令可以罗列出当前共有哪些软件包。由于软件包的数目可能非常之多,这里我们可以使用 grep 命令进行筛选
1.3 yum源更新
如果当前你使用的是云服务器,那么你使用的yum源很可能已经配置好了。如果你当前使用的是虚拟机,那么可能使用的yum源不是国内的。我们以CentOS7为例更新yum源,如果读者有其它困惑,可以自行搜索读取更加专业细致的信息。
⭐进入yum源配置文件夹 cd /etc/yum.repos.d/ ⭐做好备份,以绝后患 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup ⭐获取国内的yum源 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo (如果wget命令没有生效,输入yum -y install wget 安装wget工具) http://mirrors.aliyun.com 阿里镜像源域名 ⭐把国内的yum源,移动到对应的目录下 mv CentOS-Base.repo /etc/yum.repos.d/
二、vim —— 文本编辑器
IDE(Integrated Development Environment)集成开发环境,用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。我们在Windows操作系统下一般就是在集成开发环境写代码的。而在Linux操作系统中,我们从编写代码、编译代码再到运行代码每一个步骤可以是独立的,也就是说我们可以使用多个软件来帮助我们完成这个过程中的每一个步骤。
2.1 vim的基本概念
我们先来了解一下vim的三种最常用的模式,分别是命令模式(command mode)、插
入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
正常模式(Normal mode)
也称为命令模式,控制屏幕光标的移动,或者进入 vim 的其它模式,任何其它模式下,按「ESC」键可回到命令行模式
插入模式(Insert mode)
在命令模式下,按「i」键进入该模式。只有在该模式下才能够通过键盘向文件输入内容
末行模式(last line mode)
也称为底行模式,在命令模式下,按「shift」+「;」键进入该模式。该模式下可以进行文件的保存或退出,也可以进行文件替换,查找字符串,列出行号等操作查看你的所有模式:打开vim,底行模式直接输入:help vim-modes
2.2 vim的基本操作
输入 $ vim test.c 命令即可通过vim工具对test.c文件进行编辑,一般情况下进入vim之后,是处于正常模式下的
这几个简短的操作可能就让有些读者望而却步了,既然vim使用起来这么不方便,为什么我们还要学习使用它呢,难道我在其它编译器上写代码不香吗?事实上,在早些年的时候,计算机是没有鼠标的,我们只能通过键盘输入指令来编辑文本,vim就应运而生了。如果仅仅只是写代码,vim肯定是比不上我们平时使用的一些软件的,但是vim也有它自己的优点2.3 vim正常模式命令集
⭐插入模式 按「i」切换进入插入模式「insert mode」,从光标当前位置开始编辑 按「a」进入插入模式后,从光标所在位置的后一个位置开始编辑 按「o」进入插入模式后,在光标所在位置的下面插入新的一行,并从行首开始编辑 从插入模式切换到命令模式 按「ESC」键 ⭐移动光标 vim可以直接用键盘上的光标来上下左右移动, 但标准情况下vim使用的是小写英文字母「h」-> "←"「j」-> "↓"「k」-> "↑"「l」-> "→" 按[gg]:进入到文本的开始位置 按[shift+g]/「G」:移动到文本的结尾位置 按[n+shift+g]/「G」:移动到文本的第n行 按「$」:移动到光标所在行的“行尾” 按「^」:移动到光标所在行的“行首” 按「#l」:光标移到该行的第#个位置,如:5l,56l 按「w」:光标跳到下个word的开头 按「b」:光标回到上个word的开头 按「e」:光标跳到下个word的末尾 按「ctrl」+「b」:屏幕往“后”移动一页 按「ctrl」+「f」:屏幕往“前”移动一页 按「ctrl」+「u」:屏幕往“后”移动半页 按「ctrl」+「d」:屏幕往“前”移动半页 ⭐复制粘贴 「yy」: 复制 光标所在行 「#yy」:复制 从光标所在行开始的共#行文本 「yw」: 复制 从光标所在位置开始到字尾 「#yw」:复制 从光标所在位置开始的共#个字 「dd」: 剪切 光标所在行 「#dd」:剪切 从光标所在行开始的共#行文本 「p」: 粘贴 缓冲区里的文本到光标所在位置 「#p」:粘贴 重复进行粘贴操作#次 注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。 ⭐撤销上一次操作 「u」:撤销上一次操作 「ctrl + r」: 取消上一次的撤销操作 ⭐删除文字 「x」: 删除 光标所在位置的一个字符 「#x」:删除 从光标所在位置开始的共#个字符 「X」: 删除 光标所在位置的前一个字符(大写的X) 「#X」:删除 从光标所在位置开始(向前数)的共#个字符 ⭐替换 「r」: 替换 光标所在位置的字符 「#r」:替换 从光标所在位置开始的共#个字符 「R」:进入替换模式(替换光标所在位置的字符),「ESC」键回到命令模式 ⭐更改 「cw」: 更改 光标所在位置的字到字尾 「c#w」:更改 从光标所在位置开始的共#个字到字尾 「shift + ~」:大小写互换(长按shift,点按~,光标右移并把光标选中的字符大小写互换)
2.4 vim末行模式命令集
在使用末行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入末行模式。
⭐列出行号 「set nu」: 输入「set nu」后,会在文件中的每一行前面列出行号 ⭐跳到文件中的某一行 「#」:「#」表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了 如输入数字15,再回车,就会跳到文章的第15行 ⭐查找字符 「/关键字」: 先按「/」键,再输入想寻找的字符串,如果第一次找的关键字不是想要的, 可以一直按「n」会往后寻找到您要的关键字为止。 「?关键字」:先按「?」键,再输入想寻找的字符串,如果第一次找的关键字不是想要的, 可以一直按「n」会往前寻找到您要的关键字为止。 ⭐保存文件 「w」: 在冒号后输入字母「w」就可以将文件保存起来 ⭐离开vim 「q」:按「q」就是退出,如果无法离开vim,可以在「q」后跟一个「!」强制离开vim 「wq」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件
vi/vim 键位图(图片源自网络搜索)
extra vim补充
extra1 批量化注释
在命令模式下,按「Ctrl + v」进入视图模式,左下角出现 - - VISUAL BLOCK - - 表示当前处于视图模式
1.「Ctrl + v」进入视图模式
2.「j」、「k」上下选中区域
3.「shift + i」
4. // 双斜杠注释
5. Esc 完成批量化
批量化删除注释:
1.「Ctrl + v」进入视图模式
2.「h、j、k、l」上下左右选中区域
3.「d」删除注释
extra2 创建文件的三种方法
1. touch filename
2. 输入重定向 >myfile.c
3. vim code.c
使用vim打开一个不存在的文件,然后保存并退出,就能够新建一个文件
extra3 vim支持多窗口工作
底行模式下输入:vs + filename 即可增加一个窗口,光标在哪个区域就表示当前在哪个文件中工作。「Ctrl + w + w」可以在多个窗口之间切换。
extra4 vim的简易配置
1. 基础配置
我们先初步理解一下vim的配置原理:vim在启动的时候,会自动扫描当前用户/home目录下的.vimrc文件(如果没有就创建一个),让.vimrc文件内部的选项生效。实际上vim配置的核心就是向.vimrc文件里面添加更多的配置选项(读者可以自行网上搜索一下有哪些vim配置选项,个性化添加)。2. 安装插件
如果还有更多较高的需求,原生的配置可能功能不全,可以选择安装插件来完善配置。同样我们需要先创建一个.vim的目录来存放vim的插件。
安装插件的原理与基础配置相仿,但是操作起来更加复杂多样,可能出现的问题也层出不穷,文章篇幅有限,不做详细介绍,读者如果感兴趣可以在网上搜索一些相关的教程。
三、gcc/g++ —— 编译器
通过前面的学习,我们已经可以使用vim写代码了(你可以通过配置你的vim让编写代码更舒适一些)。接下来再向大家介绍一下Linux下常用的编译器gcc/g++(编译C语言可以使用gcc/g++,编译C++只能使用g++)
3.1 gcc/g++的使用演示
我们先通过实际操作演示一下(如果当前你的Linux没有安装gcc/g++,yum install gcc、yum install gcc-c++安装一下,安装完成后which gcc/g++查看是否安装成功)
注意:Linux系统中,文件的后缀是无意义的,但是不代表gcc/g++不关心文件的后缀。文件的后缀错误会导致gcc/g++编译失败
3.2 程序的翻译
源文件->预处理->编译->汇编->链接->可执行程序
注意:下面的内容仅作了解!了解这个过程可以帮助我们更好的认识程序的翻译。
⭐预处理
我们先通过实际操作带读者学习一下相应的操作需要的指令,比较预处理前后的代码
我们再来看一段代码经过的预处理后的效果
通过条件编译,可以实现对代码的动态裁剪。
现实生活中,有很多软件会根据用户的身份开放不同的功能,如:Visual Studio、idea、Xshell、VMware……很多软件都会有 个人/免费/社区版 和 专业版 之分,相比之下,免费版功能齐全,足够我们一般的学习以及使用了;专业版功能非常丰富,但是会收取一定的费用。如果你开了一家公司,开发出一个类似的软件,那么你认为这个软件背后的源代码需要维护两份吗(免费版一份源代码,专业版一份源代码)?显然是一份代码,我们可以通过条件编译使一份代码可以同时发挥两种不同的功能(免费版和专业版),如此可以节省更多的资源成本。
⭐编译
⭐汇编
⭐小结
可能看完上面介绍与分析你会有很多疑惑,但是我们需要学习的指令仅有一条:
gcc code.c -o mybin.exe
tips:如果你记不住预处理、编译、汇编对应的指令选项,可以看看键盘左上角的"Esc"
3.3 动静态库的概念与理解
3.2 中我们只介绍了程序的翻译中的预处理、编译、汇编,接下来我们详细地介绍一下链接。实际上,我们目前为止所写的所有代码都是站在巨人的肩膀上的(已经有人为我们写好了可以直接使用的函数接口),我们仅需包含一个头文件,就可以不费任何功夫地使用里面的函数。当然这些头文件已经提前预装在我们的Linux下的某个目录中了
在解释什么是链接之前,我们需要先认识一个新的概念——函数库
我们的C程序中,并没有定义"printf"的函数实现,而且在预编译中包含的"stdio.h"中也只有该函数的声明,没有定义函数的实现,那么,是在哪里实现"printf"函数的呢?
系统把这些函数实现都放到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到
系统默认的搜索路径"/usr/lib"下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能使用函数"printf"了,而这也就是链接的作用。我们得到的可执行程序 = 我们写的代码 + 头文件 + 库
头文件和库本质上都是文件,所谓的搭建开发环境,实质上就是下载安装并拷贝头文件和库到开发环境的特定路径下(一定要能够被编译器自己找到)。
我们再来了解一下动静态库的概念
动态库(动态链接):是C/C++或其它第三方提供的所有方法的集合,被所有程序以链接的方式关联起来(库中的所有函数,都有入口地址,所谓的动态链接,其实就是要连接的库中的函数地址拷贝到我们的可执行程序的特定位置)
静态库(静态链接):是C/C++或其它第三方提供的所有方法的集合,被所有程序以拷贝的方式,将需要的代码拷贝到自己的可执行程序中
动静态链接的优缺点:
动态链接形成的可执行程序占用空间较小,比较节省资源,但是一旦动态库没了,所有依赖这个库的程序就都无法运行了;静态链接可以独立运行,不依赖于库,但是占用空间较大,比较浪费资源。
tips:如果你使用的是云服务器,那么一般情况下系统是没有安装静态链接的,如果需要请参考下面的指令
sudo yum install -y glibc-static # 安装C静态库 sudo yum install -y libstdc++-static # 安装C++静态库
四、make/Makefile —— 自动化构建工具
make是一条命令,makefile是一个在当前目录下存在的一个具有特定格式的文本文件,两个搭配使用,就能够完成项目自动化构建(一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。所谓的自动化构建,就是只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率)
4.1 make/makefile的使用演示
我们先通过实际操作带读者了解一下其中细碎的知识点
4.2 了解make/makefile的基本原理
接下来我们再了解一下make/makefile的基本原理
⭐make/makefile是怎样识别文件的新旧的呢?怎样理解被"PHONY"修饰的目标文件,总是可以被执行的这句话的涵义?
⭐make/makefile 是具有依赖性的推导能力的当我们执行make命令的时候,make会在当前目录下找名为"Makefile"或"makefile"的文件。如果找到了makefile文件,它会从上至下查找文件中的第一个目标文件(mybin)。如果该文件不存在,或是mybin所依赖的code.o文件的Modify时间要比目标文件新(可以用 touch 测试),就会执行后面所定义的命令来生成mybin这个文件。依此类推,如果mybin所依赖的code.o文件不存在,那么make会在当前文件中继续查找目标为code.o文件的依赖性,如果找到了(code.s)就根据依赖关系逐步回退,直到生成mybin文件。这就是make/makefile的依赖性的推导能力的,make会一层又一层地去寻找文件的依赖关系,直到最终编译出第一个目标文件。
注意:在查找文件的过程中,如果出现错误(比如最后被依赖的文件找不到),那么make就会直接结束查找,并且回显错误信息。make只具有文件的依赖性的推导能力,如果在找了依赖关系之后,冒号后面的文件并不存在,那么make不做任何处理。extra make/makefile 补充
五、编写小程序 —— 进度条
5.0 缓冲区与回车换行
5.1 简单原理版本
我们先简单地大致了解一下代码结构
接下来就上手逐步带你实现一个简易版的进度条
当然,这只是一个进度条,并没有真正发挥它应有的作用(实时显示下载安装的任务进度),如果你对源代码感兴趣,我已经分享在下面啦,但是不要走开,工程实践版本的进度条更具有实际意义,更加值得我们学习
FILE->main.c #include "process.h" int main() { process(); return 0; } /// FILE->process.h #pragma once #include <stdio.h> void process(); /// FILE->process.c #include "process.h" #include <string.h> #include <unistd.h> #define SIZE 101 #define MAX_RATE 100 #define STYLE '#' #define SLEEPTIME 1000*200 const char *str="|/-\\"; void process() { // version 1 int rate=0; //char bar[SIZE] = {0}; char bar[SIZE]; memset(bar, '\0', sizeof(bar)); int len = strlen(str); while(rate <= MAX_RATE) { printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%len]); fflush(stdout); usleep(SLEEPTIME); bar[rate++] = STYLE; } printf("\n"); }
5.2 工程实践版本
如果需要进度条和实际的下载安装任务契合起来,就不能一次性把进度条全部打印出来,而是需要根据任务进度来实时更新进度条
源代码:
FILE->main.c #include "process.h" #define TARGET_SIZE 1024*1024 // 1M #define DSIZE 1024*10 // 10kb // 模拟下载 void download(callback_t cb) { int target = TARGET_SIZE; int total = 0; while(total < target) { // 休眠模拟下载花费的时间 usleep(SLEEPTIME); total += DSIZE; int rate = total*100/target; cb(rate); // 回调函数 } printf("\n"); } int main() { download(process_v2); return 0; } /// FILE->process.h #pragma once #include <stdio.h> #include <string.h> #include <unistd.h> #define MAX_RATE 100 #define SIZE 101 #define STYLE '#' #define SLEEPTIME 1000*200 typedef void (*callback_t)(int); void process_v1(); void process_v2(int rate); /// FILE->process.c #include "process.h" const char *str="|/-\\"; void process_v2(int rate) { // version 2 static char bar[SIZE] = {0}; int len = strlen(str); if(rate <= MAX_RATE && rate >= 0) { printf("[%-100s][%d%%][%c]\r", bar, rate, str[rate%len]); fflush(stdout); bar[rate] = STYLE; } if(rate == MAX_RATE) memset(bar, '\0', sizeof(bar)); }
5.3 C语言扩展(风格美化)
代码轻量级,仅作参考,如有需要,建议读者上网搜索更优代码
FILE->main.c #include "process.h" #define TARGET_SIZE 1024*1024 // 1M #define DSIZE 1024*10 // 10kb // 模拟下载 void download(callback_d cb) { int testcnt = 80; int target = TARGET_SIZE; int total = 0; while(total <= target) { usleep(SLEEPTIME); total += DSIZE; double rate = total*100.0/target; // 测试进度条停滞的情况,稍等几秒 if(rate > 50.0 && testcnt) { total = target/2; testcnt--; } cb(rate); // 回调函数 } cb(MAX_RATE); printf("\n"); } int main() { download(process_v3); return 0; } /// FILE->process.h #pragma once #include <stdio.h> #include <string.h> #include <unistd.h> #define MAX_RATE 100 #define SIZE 101 #define STYLE '#' #define STYLE_BODY '=' #define STYLE_HEADER '>' #define SLEEPTIME 1000*60 typedef void (*callback_t)(int); typedef void (*callback_d)(double); void process_v1(); void process_v2(int); void process_v3(double); /// FILE->process.c #include "process.h" const char *str="|/-\\"; void process_v3(double rate) { // version 3 static char bar[SIZE] = {0}; static int cnt = 0; int len = strlen(str); if(rate <= MAX_RATE && rate >= 0) { cnt++; cnt %= len; printf("加载中...\033[44m%-100s\033[0m[%.1f%%][%c]\r", bar, rate, str[cnt]); fflush(stdout); if(rate < MAX_RATE) { bar[(int)rate] = STYLE_BODY; bar[(int)rate+1] = STYLE_HEADER; } else { bar[(int)rate] = STYLE_BODY; } } if(rate == MAX_RATE) memset(bar, '\0', sizeof(bar)); } // v3 优化了旋转光标,v2旋转光标依赖于rate,故进度条停滞会导致光标停止旋转 // 优化了rate的数据类型<double> // 解释printf中的"\033[44m%-100s\033[0m" \033[44m到\033[0之间的区域染为蓝色
测试效果:
六、认识git/gitee/github
由于文章篇幅有限,作者在此仅介绍最常用的基础指令,并且帮助读者理解一下git的基本原理
6.1 什么是git
Git(The stupid content tracker, 傻瓜内容跟踪器。Linus Torvalds 是这样给我们介绍 Git 的。)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 [1] 也是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。
——摘取自百度百科
那么,版本控制器又是什么呢?举一个通俗的例子,现在你写了一篇博客并发表了,过了几天你请你的老师帮你看一下有哪些可以改进的地方。你听完后觉得有道理,下去大改一番,又去向老师寻求建议,听完老师的建议后你又修改了一番,最后老师却说:算了算了,还是第一版的比较简洁明了。这时候你该怎么办呢?如果你把每一个版本的博客都保存记录下来了,就不会为此感到忧愁,这个保存每一个版本的做法就可以称为手动的版本控制了,而用于存放保存的各个版本的空间则被称为仓库。而git则是通过编程自动化完成这个功能(按照变化管理被保存的内容,最终可以提供变化过程中的各个版本)的软件,除此之外它还要自己的网站:gitee/github
6.2 git的特点
1. git 是一款软件,它既是客户端,又是服务器
2. git 只会记录内容的变化(并非保存每个版本的所有内容)
3. git 是分布式软件,是去中心化的
gitee/github 是基于git软件搭建的网站,让版本可视化(降低学习成本)
6.3 git的使用
gitee/github网址:
Gitee - 企业级 DevOps 研发效能平台面向企业提供一站式研发管理解决方案,包括代码管理、项目管理、文档协作、测试管理、CICD、效能度量等多个模块,支持SaaS、私有化等多种部署方式,帮助企业有序规划和管理研发过程,提升研发效率和质量。https://gitee.com/新建仓库并开源链接Linux用户的图示教程
完成了上述操作,我们接下来介绍一下git的三板斧
extra .gitignore文件
vim .gitignore 可以打开并编辑.gitignore文件,凡是(以后缀形式)被记录在.gitignore中的类型的文件,都不会被提交至仓库
七、gdb —— 调试器
7.1 什么是debug && release
程序的发布方式有两种,debug模式和release模式。Linux gcc/g++编译的可执行程序,默认是release模式的。如果要使用gdb调试,必须在源代码生成可执行程序的时候,加上 -g 选项修改为debug模式。
我们进一步观察证明一下debug模式和release模式是存在区别的有人可能就会觉得奇怪了,为什么需要两个发行版本呢?都使用debug版本不好吗?实际上用户使用的程序都是release版本的,release版本对代码做了一些优化
7.2 使用 gdb
gdb基础常用指令一览
gdb mybin # base ctrl d 或 quit:退出 list(l) 行号/函数名: 显示mybin的源代码,每次展示10行(或列出此函数的源代码) run(r): 运行程序/开始调试 next(n): 逐过程(会一步完成整个函数调用 step(s): 逐语句(会进入函数的内部 set var 变量名: 修改变量的值 (print)p 变量名: 打印变量的值 # 断点 break(b) 行号/函数名: 在此行(或此函数的第一条语句处)设置断点 info(i) n: 查看序号为n的断点的信息 delete(d) n: 删除序号为n的断点 disable n: 禁用序号为n的断点 enable n: 启用序号为n的断点 i/d b: 查看/删除所有断点 # 监视 display 变量名: 跟踪查看一个变量,每次停下来都显示它的值 undisplay 序号: 取消对序号指代的变量的跟踪 # 代码块定位 until 行号: 跳至该行 finish: 运行到当前函数的结尾 continue(c): 运行到下一断点处 # 堆栈 breaktrace(bt): 查看调用堆栈 info(i) locals: 查看当前栈帧局部变量的值 @0. | number 查看代码 @1. gdb会记录上一次使用的指令,可以通过Enter快捷使用上一次使用的指令 @2. 每次调试过程中,断点序号是递增的,一旦退出调试,所有断点都将被清除