目录
第二步:编写makefile文件,管理工程,实现自动化编译(.o)
第三步:使用make命令执行makefile文件中的指令集:
Linux系列学习目录:
Linux系列学习 (一) - Linux的系统安装(MacOS)、文件系统、基本命令
在上篇文章中,我们基本了解了基于Mac系统的Linux系统安装、现如今各式各样的Linux版本、Linux的文件系统、Linux中常用的命令。这一篇文章我们将对Linux系统中自带的VIM编辑器进行了解和学习,VIM编辑器本身具有强大的功能以及多种多样的插件,学习VIM也是非常重要的。同时因为Mac系统与Linux系统有着极高的相似度,这篇文章的对于VIM的学习我会直接在Mac系统上进行,所有的操作在Linux中也都可以复刻。
cat命令全全称(concatenate),作用主要为查看单个或多个文件,cat命令还有将多个文件进行合并以及对文件的重定向功能。
用cat命令来对文件内容进行显示:

例如我在这里创建了test目录下创建了两个文件a.txt和b.txt,两个文件中的文本信息如图:

我使用cat命令将两个文本文件进行合并,合并后的文件名叫c.txt,输入命令:
cat a.txt b.txt > c.txt

那么什么是重定向呢?
输入命令:
cat > c.txt
系统提示我们进行输入,如图我输入了两行数据,第一行为1234,第二行为5678,输入完成后按Ctrl + D结束输入,然后我们再使用cat命令对c.txt文件进行查看:
如图,我们使用了cat的重定向功能在不启用vim编辑器的情况下直接对c.txt文件进行了编辑并且自动保存。
man命令用于查看命令的帮助手册,例如我在这里要查看rm命令,这里介绍rm命令的作用就是移除文件或者文件夹,且后面还有不同的后缀名对应的功能。

head命令与cat命令类似,用于显示文件前n行的内容,具体用法为:
head -n 文件名
例如刚才合并后的c.txt文件,总共有两行内容,我们如果只需要显示文件的第一行内容,则输入命令:
head -1 c.txt
如图:

tail命令用于显示文件后几行的内容,它与head命令对立,具体用法为:
tail -n 文件名
例如在这里我需要显示c.txt文件的后一行内容,则输入命令:

find命令用于在目录树中搜索指定的文件,具体用法为:
find 路径 -name 文件名:
例如我在这里需要获取到Desktop目录下名为main.c的文本文件路径,则输入命令:
find /Desktop -name main.c
如图:

如图,获取到main.c文件的路径为/Desktop/test/main.c
同样,如果我们查找不到该文件,则会不显示路径:

grep命令用于过滤出文件中指定字符串的行,具体用法为:
grep “字符串” 文件名
例如我要过滤出来main.c文件中包含int字符串的行,先对main.c文件中的文件进行显示,输入命令:
cat main.c
再对文件进行过滤:
grep "int" main.c
如图:

将grep命令与管道“|”结合进行使用的作用为将前一个命令的输出结果作为后一个命令的输入,具体的用法为:
路径 | grep 过滤名称
例如我在这里需要搜索位于桌面的test文件夹中所有以.c结尾的文件,则输入命令:
ls /test | grep .c
如图:

tar命令用于将文件打包,打包文件是创建压缩文件的第一步,tar命令的具体用法为:
- c 创建包文件
- f 指定目标为文件而不是设备
- v 显示详细过程
- t 显示包中的内容而不释放
- x 释放包中的内容
- z GNU 版本新加的,使得 tar 有压缩和解压的功能
例如我要打包main.c add.c mul.c 这三个文件,输入命令:
tar cvf tar.tar add.c mud.c main.c//参数名称和作用参考上方

如图,生成了一个后缀名为tar的文件包。
第二步,生成打包后的压缩文件,输入命令:
gzip tar.tar

同样,我们也可以将打包和压缩的步骤一步进行,一步压缩和解压命令:
tar zcvf file.tar.gz main.c add.c mul.c
如图,一步生成了一个压缩文件:

压缩文件生成了,我们又怎样对压缩文件进行解压呢?
输入命令:
gzip -d tar.tar.gz

vim编辑器有几种模式,如图:

- 1. a //进入到当前光标后开始编辑
- 2. A //进入到当前光标所在行的行末开始编辑
- 3. i //进入当前光标位置开始编辑
- 4. I //进入当前光标所在行的行头开始编辑
- 5. o //进入当前光标下一行开始编辑
- 6. O //进入当前光标上一行开始编辑
- 1. : //对文本的设置或保存工作
- 2. / //对文本进行全文向下搜索字符串 string
- 3. ? //对文本进行全文向上搜索字符串 string
- 1. :w //保存文本
- 2. :q //退出编辑
- 3. :wq //保存并退出
- 4. :q! //强制退出
- 5. :w newfile //另存为
- 6. :set nu //显示行号
- 7. :set nonu //取消行号
- 8. : set hlsearch //设置高亮搜索
- 9. : set nohlsearch //取消高亮搜索
- 10. :n,ms/oldstring/newstring //替换整个文本每行的第一个oldstring
- 11. :n, m s/oldstring/newstirng/g //替换整个文本所有的 oldstring
- 12. /string //向下搜索string
- 13. ?string //向上搜索 string
- 1. n dd //删除光标开始向下的 n 行
- 2. n yy //拷贝光标开始向下的 n 行
- 3. p //粘贴
- 4. u //撤销上一次操作
- 5. ctrl + r // 恢复上一次撤销操作
- 6. r //替换一个字符
- 7. shift + 6 //光标移动到当前行的行头
- 8. shift + 4 //光标移动到当前行的行尾
- 9. shift + g //光标移动到整个文本的最后一行
- 10. gg //光标移动到整个文本的第一行
- 11. n shift + g //光标移动到第 n 行
- 12.dnshift+g //删除光标到n行的内容
- 13. y n shift+g //拷贝光标到n行的内容
在终端中输入VIM之后,你将会看到如下界面,:

我画红线处即是vim编辑器的版本,现在我们发现,我们按键盘上绝大多数的键,这个界面都是没反应的,唯有我们输入“:”键才能在界面的左下角输入文字,这就是命令模式。
接下来我们介绍几个命令模式中的命令:
ndd命令用于文本文件中直接按行删除,注意这里的n代表的是你从光标开始需要删除几行
输入9行1至9的数据,如图:

输入命令:
9dd
如图,直接删除了9行的数据:

如果我们要恢复之前的文本内容,在vim编辑器中也有撤销命令,输入命令:
u
如图,撤销了刚才的删除操作:

nyy命令用于拷贝连续的n行内容,例如我现在要复制前三行的内容(1,2,3),输入命令:
3yy
如图,在左下方出现了一句话:

p命令用于粘贴拷贝过后的内容,例如我们刚才复制了前三行的内容,现在我们将前三行的内容粘贴至文件的末尾,输入命令p:

如图,成功地将前三行的内容粘贴到了末尾。
如图我输入gg命令,成功将光标移到了开头:

如图我输入G命令,成功将光标移到了文件的末尾:

如图:

如图:

n代表你要跳转到第几行,例如我现在要跳转到第6行,输入命令6G:

我们在编辑模式下按Esc键即可进入命令模式,再输入“:”则可以进入到末行模式,同样,末行模式也有对应的命令,我们将对这些命令做介绍:
wq命令用于将编辑好的文件保存并退出。
w命令是只保存。
q命令是只退出不保存。
q!命令为强制退出,不保存。
如果我们要进入到VIM的编辑模式,在键盘上按下“I”键,终端界面的左下角会出现“INSERT”这个单词,如图:

出现了“INSERT”,我们就可以在vim编辑器中输入内容了,这就是编辑模式。
如果我们这时在vim中随便输入一些数字123,并打算保存退出,输入命令:wq,如图:

VIM编辑器会提示我们还没有文件名字,我们输入“wq:+文件名” ,例如我在这里输入“:wq test.c”,文件就会以test.c为名保存在用户主目录下。
set nu命令一般用于给vim编辑器中的代码显示行号,当我们处于vim的初始模式时,并没有行号,如图,我在vim中写了一个基于C语言的Hello程序,初始状态是没有行号的,如图:

我们按“Esc”键,并输入“:set nu” 命令,即可让程序代码显示行号,如图:

syntax on命令一般用于在vim中显示语法高亮,如图我们在vim中虽然设置完了行号,但是代码的初始状态依然没有像VScode、Clion这些经典的编辑器那样有颜色,反而所有的程序代码都是黑色的:

我们按“Esc”键输入“:syntax on”命令,即可让代码显示语法高亮,如图:

上面我们讲了几种vim的基础命令,当我们在vim中配置好了之后并重新进入文件的时候,我们就会发现,之前我们的所有配置就会消失不见。我们现在要做的就是一劳永逸,让我们一次的配置永久性地发挥作用。
首先我们要明确的是,vim的配置文件名为vimrc,所有有关vim的配置我们都可以在vimrc文件中进行,当然配置vimrc文件的命令也与我们使用vim编辑其他文件的时候是一致的,我们在终端中输入命令:
vim ~/.vimrc
输入完命令之后,进入到vimrc文件中,如图:

现在我们按“I”键进入“INSERT”模式,开始对vimrc文件进行配置,输入上面说的命令:
syntax on
set nu

按“Esc”键退出,按“:” 键进入命令模式,输入“wq”保存并退出。然后我们此时再次编辑刚刚创建好的test.c文件,如图:

如图,当我们配置好了vimrc文件并再次进入test.c文件时,我们的设置并没有消失而是永久生效了。
同样,我们也可以在vimrc文件中自行配置其他我们想要的配置,例如自动对其、tab键累计空出4个空格等等,我们现在在vimrc中添加一些常用的命令,这里我们给出一些常用的vim配置仅供参考;
- //设置语法高亮
- syntax on
-
- //设置行号
- set nu
- //(set nonu)为取消行号
-
- //设置自动对其、对其、标尺、智能对其
- set autoindent
- set cindent
- set ruler
- set smartindent
-
- //将TAB键和4个空格区分开来,与上方makefile文件中的gcc命令前置TAB键问题相吻合
- autocmd FileType make set noexpandtab
-
- //将tab键替换为4个空格,这样有利于语法对其
- set tabstop=4
- set shiftwidth=4
- set expandtab
- set smarttab
-
- //将编程中常用的符号改为双写并将光标置中
- inoremap { {}
- inoremap ( ()
- inoremap < <>
- inoremap [ []
- inoremap " ""
- inoremap ' ''
这里我只写了vim的初级配置,当然网上还有很多其他vim的配置,大家如果需要可以自行查找并添加。
我们知道无论是在Windows、MacOS、Linux哪一个系统中,文件都是一个基于外存的概念,文件通常存储在磁盘或者U盘中,在Windows系统中,文件一般由两部分构成——文件名和文件类型。在Linux中,文件又被分为不同的文件属性,他们分别为:
r(read)读取:对文件而言,具有读取文件内容的权限;对目录来说,
具有浏览目 录的权限。
w(write)写入:对文件而言,具有新增、修改文件内容的权限;对目
录来说,具有删除、移动目录内文件的权限。
x(execute)执行:对文件而言,具有执行文件的权限;对目录了来说
该用户具有进入目录的权限。
文件又分为可执行文件和不可执行文件,例如在C语言中.c(源文件)或.h(头文件).o(二进制目标文件)都属于文本文件都是不可执行文件,.exe就是可执行文件。
程序的编译和链接过程:

这里我们对这几个过程进行解释:
预处理阶段:
预处理主要的工作就是将头文件插入到所写的代码中,生成扩展名为.i的文件替换原来扩展名为.c的文件,但是原来的文件仍然是保留的,只是执行过程中的实际文件发生了改变。
编译阶段:.i文件中的代码翻译成特定的汇编语言。编译器首先要做的就是检查代码的规范性,如果有错误,这个阶段就通不过,用以确定代码的实际要做的工作。检查无误后,编译器将代码全部翻译成汇编语言,同时将文件的扩展名从.I编程.s。
汇编阶段:汇编过程将上一步的汇编代码转换成机器码(也就是我们说的01010100这种计算机能读懂的二进制编码),这一步产生的文件叫做目标文件.o文件,.o文件就是二进制格式的。
链接:链接过程就是将多个目标文件以及所需的库文件( .so)链接成最终的可执行文件。
例如我们在这里写一个简单的helloworld程序,我们通过命令来对文件编译连接的过程进行演示和分析。
创建一个普通文件test1026.c,并使用vim编辑器对它进行编辑,写下helloworld程序的C代码:

对test1026.c进行预编译操作,输入命令:
gcc -E test1026.c -o test1026.i

如图,生成了一个test1026.i文件,我们通过vim编辑器对这个文件进行查看:
如图,是一些路径和一些C语言。
对test1026.i文件进行编译操作,输入命令:
gcc -S test1026.i -o test1026.s

如图,生成了一个名为test1026.s的文件,按照上面对文件类型的介绍,这个文件中应该是将C语言翻译过后的汇编语言,我们通过vim编辑器对这个文件进行查看:

如图红圈所示就是C语言翻译完之后的汇编代码。
对test1026.s文件进行汇编操作,输入命令:
gcc -c test1026.s -o test1026.0

如图,出现了一个test1026.0的文件,我们通过vim编辑器对这个文件的内容进行查看:

这就是二进制格式的.o文件内容,可以发现,这时的文件内容大致已经变成了机器码。
对test1026.0文件进行链接操作,输入命令:
gcc test1026.0 -o test1026
如图生成了一个名为test1026的文件:

这个test1026,就应该是按照步骤走的最终的可执行文件了,我们通过./命令,来执行当前目录下的test1026,检验一下它是否真的可执行,输入命令:
./test1026

如图,程序执行成功!
Linux中,如果我们已经使用vim编辑器写好了程序,其实只需要一步就可以生成可执行程序,我们拿上面的文件举例子,只需要在编写好test1026.c这个文本文件后输入命令:
gcc -o test1026 test1026.c
这条命令可以直接输出最终的可执行文件。
在之前我们的这篇文章:
数据结构系列学习(二) - 顺序表详解(Contiguous_List)
曾经说到过IDE中源文件与头文件之间的关系,当我们写一个项目时,我们通常要讲个待实现的函数在头文件(.h)中进行声明,然后将头文件中声明的函数功能在对应的源文件(.cpp)中进行实现:
例如我们在Linux中进行文件编译时,就在头文件中进行函数的声明,再源文件中进行函数功能的具体实现,在这里我们写一个简单的两数相加的函数在头文件中并在源文件中进行引用:
头文件中的函数声明:

源文件中对头文件的引用:

编译运行:
输入命令:
gcc -o main main.c

如图,程序执行成功。
在前面我们说过,引用头文件时,一般采用的是"" 符号,因为如果使用<>符号,就会默认在系统路径下进行查找,如果我们此时将main.c文件中的#include"add.h"改为#include

编译发生了错误,因为系统并没有在默认头文件路径下找到add.h头文件,Linux系统中对头文件的存储默认都放在/usr/include文件下, 那么此时我们既然知道头文件的默认路径,我们只需将当前路径下的add.h头文件迁移至此路径即可,#include
输入命令:
mv add.h /usr/include
再次编译并运行:

如图,编译成功且程序运行成功。
但是这里需要注意的是,/usr/include路径一般存放的都是C标准库文件(例如stdio.h、stdlib.h),一般情况下我们自定义的头文件不要放到这个路径下面,我们此次演示只是为了强行让main.c文件中的#include
输入命令:
- cd /usr/include
- mv add.h /home/parallels/dir
例如我们要通过vim编写一个加法函数和一个乘法函数并且要在main.c文件中对这两个函数进行调用。
add函数:

mul函数:

在main.c程序中对add和mul函数进行调用:

创建makefile文件,输入命令:
touch makefile
使用vim编辑器对makefile文件进行编辑,输入指令:
- 1 all:main
- 2
- 3 main:add.o mul.o main.o
- 4 gcc -o main add.o mul.o main.o
- 5
- 6 add.o:add.c
- 7 gcc -c add.c
- 8 mul.o:mul.c
- 9 gcc -c mul.c
- 10 main.o:main.c
- 11 gcc -c main.c
- 12 clean:
- 13 rm -rf *.o main
如图:

保存退出。


如图,函数调用完毕,程序执行成功。
在使用make命令时, 终端可能会出现两种情况的报错,这里我们分开来进行讨论:
第一种报错:
makefile:4: *** missing separator. Stop.
这个错误的主要原因就是在我们之前配置vimrc的时候,设置TAB键等于4个空格,如图,我们敲击TAB键,gcc命令的那一行是不会被识别的:

我们返回根目录下的vimrc文件使用vim编辑器对vimrc文件进行编辑,在vimrc文件中在我们设置TAB键 = 4个空格的命令上方加上这样一条命令:
autocmd FileType make set noexpandtab
如图:

接下来我们再重新使用vim编辑器对makefile文件进行编写:
这次我们再用TAB键就不会出现上面的那种错误的情况了:

如图,命令全部识别出了出来,问题解决~
再就是还有一个错误,就是系统根本没有安装make的依赖包导致系统无法识别make命令导致出来的错误:
MacOS输入命令:
brew install make
在终端执行完命令之后,如图:

完成之后,我们输入命令:
make --version
用来检测我们的安装是否成功以及我们安装的make版本,如图:

如图,安装完成,make的版本为3.81
这里再补充两个其他系统安装make依赖包的命令。
CentOS输入命令:
yum install make
Ubuntu系统输入命令:
apt install make
这就是通过makefile文件来对多个工程文件进行管理的举例,当我们在书写一个项目例如,顺序表、单链表、循环链表的时候通常需要多个文件(头文件、对头文件中声明函数具体实现的源文件、测试文件)的协同工作,我们就可以使用makefile对这里的多个工程文件进行集中编译,生成最终的可执行文件。
我们使用Vim编辑器完成对C程序的编写之后,事情总是不可能一步到位的,除了程序语法错误以外,程序的执行过程中也有可能出错,这时就凸显出了调试的重要性,Visual Studio、Clion这些经典的IDE都有调试的功能,且在他们的图形化界面中,调试操作一般都是以按钮操作完成的。在visual studio编译器中,一般都存在两种模式 ,
那么在Vim,我们又如何进行程序的调试呢?由此,我们引入Gdb调试器,Gdb调试器是一个可以在Vim中实现调试的工具,首先我们要做的就是安装Gdb调试器,在这里我写出两种系统(MacOS、CentOS)安装Gdb调试器的方法:
在MacOS中,首先我们打开终端,通过brew来安装,输入命令:
brew install gdb

如图,在终端中出现了gdb调试器的版本,就代表我们已经安装完成。

如图,没有安装gdb调试器的情况下,系统是找不到gdb命令的。
在CentOS中我们通过软件包管理工具yum来安装gdb调试器:
如果你的CentOS版本是8,这时你可能会遇到第一次终端报错:

原因所在:在2022年1月31日,CentOS团队从官方镜像中移除了CentOS的所有软件包,CentOS8在2021年12月31日已经结束了生命周期。
解决方法:更换下载源:
输入命令:
- sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-*
- sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*
更换完成后继续输入:
yum install gdb
如果下载源正常,则可以开始下载,如图:
安装中:

安装完成:

《程序员的自我修养》
《鸟哥的LINUX私房菜》
《LINUX平台应用开发教程V5》