通过前几篇博客的学习,相信大家已经对Linux
系统有了一个初步的认知和了解,那么本篇博客就对所学内容进行有机整合,进入Linux系统编程的阶段.
- 前面讲过在
Linux
环境下进行编程需要以下 4 个工具:
- 代码编辑器 vim
- 编译器 gcc
- 调试器 gdb
- 工程管理工具 makefile
vim
已经有专门一篇博客讲过它的用法与内容了,所以这次主要介绍其他三位主角,看看他们究竟是通过怎样的操作实现编程的.
[ 这里演示的编程操作以C语言
为例 ]
整体步骤
1. 创建文件
输入指令创建 :
vim hello.c
注: hello.c
是你希望创建文件的文件名
2. 键入代码
在hello.c
文件中i
进入插入模式,输入好程序代码esc
, :wq
保存退出
- 注: 这里不能像在
Windows
系统中一样,为了使打印结果不一闪而逝加入的system("pause");
这一语句,因为Linux系统中不支持.
3. 编译
通过gcc + 目标编译文件名
,完成对其的编译,正常编译完成没有反馈
这里编译成功之后,我们可以额外的通过ll
先查看一下编译产生的文件
我们可以看到,这个a.out
文件就是默认编译产生的文件
4. 执行
通过相对路径方式执行这个a.out
文件,打印结果就顺利显示在界面上了:
./a.out
如果你完成了上述操作,恭喜完成了第一次Linux
系统环境下的编程.
有了第一次成功,相信以后多样的代码都可以在Linux环境下顺利执行
接下来,我们深层次地理解一下编程过程中的这些工具与文件:
-
a.out
是什么?
我们通过指令file a.out
详细查看一下这个文件:
通过结果我们大致可以得知:
它是一个Linux下的标准ELF
格式文件,并且executable
说明它是一个可执行文件,所以我们才可以通过./
的方式直接执行它 -
为什么名为
a.out
,可以有其他名称吗?
我们可以在gcc
指令编译时就设置好 输出文件的文件名,如下:
gcc hello.c -o hello
-o
意为- output
,后面接 希望输出文件修改的文件名
我们ls
罗列了一下文件夹中的文件,发现确实是通过指令进行了名称修改
用了这么多次的gcc
到底是什么?
gcc
它是一个编译器
GCC 原名为 GNU C
语言编译器(GNU C Compiler),因为它原本只能处理 C语言
现已被大多数类
Unix
操作系统(如Linux
、BSD
、Mac OS X
等)采纳为标准的编译器,GCC同样适用于微软的Windows
.
GCC 通过快速扩展,变得可处理C++
。后来又扩展能够支持更多编程语言,如Fortran
、Pascal
、Objective-C
、Java
、Ada
、Go
以及各类处理器架构上的汇编语言等
通过gcc
我们可以把编译过程拆解开
● 编译的四个最核心的步骤/整体过程:
- 预处理
a).宏替换
宏相当于文本替换,相当于字符串的复制粘贴.
如果在程序首部#define SIZE 8
,就会将整个文件中的SIZE
在预处理阶段全部替换为8
b).去注释
对部分代码进行解释的注释是没有必要编译的,它仅供提高代码可读性
c).条件编译
避免重复编译,提高代码效率
[https://mp.csdn.net/mdeditor/85244894# ]
d).替换头文件
将包含的头文件复制引入函数,包括运用到的函数/模块等等
我们修改一下代码,在其中加入宏定义,如图所示,看看预处理之后的效果是什么样子
输入指令:
gcc -E hello.c -o hello.i //大写E
-E
是预处理指令hello.i
就是对于源文件预处理产生的文件
回车之后没有反馈,我们vim
查看一下这个hello.i
文件内部
可以看到里面相比于之前寥寥几行的代码主体多出了很多行代码,其实这个就是对头文件进行了替换
这里当时的SIZE
也直接变成了8,说明确实是在编译之前就进行了文本替换,一个头文件、宏的展开会产生大量的代码。
- 编译
【将c语言代码文件变成汇编代码,也是高级语言向机器语言过渡的一个中间环节】
输入指令:
gcc -S hello.i -o hello.s //大写S
hello.s
文件保存了我们代码的汇编结果,我们再次vim
查看内部
我们发现已经有些阅读天书的感觉了,但是仍旧有些字段我们是可读的
- 注:不同的CPU支持的汇编语句、机器指令是有差别的
- 汇编
【将汇编代码变成二进制的机器码】
输入指令:
gcc -c hello.s -o hello.o //小写s
vim
查看,我们发现现在相对于前两次查看是彻底看不懂了,它是二进制的机器语言,大部分人类看不懂,但是机器可以看懂。
- 链接
【把多个.c
文件编译成的机器码进行汇总,比如函数在a中定义,并在b中调用,那么不进行链接就无法正常执行】
输入指令:
gcc hello.o -o hello
这次终于对前面文件没有依赖了,直接运行指令就可以完成链接
我们ls
查看一下当前文件夹在过程中产生的文件:
发现红色框选的是演示过程中依赖的文件,而最后产生了蓝色的可执行的hello
文件
-
是否和篇头的编译过程一样呢?
我们一样使用./ + 文件名
进行验证,正确执行,说明二者等效。
如上图,正确打印出我们开头设置的宏定义参数,至此,对编译过程的演示就告一段落了 -
小结
简单的记忆方法:我们使用的预处理指令顺序为E --> S --> c
,相当于esc
键,位于键盘左上角的键
这里只是罗列几个常用命令 , 更多
gcc
指令后缀请客官自行使用man
手册查看.
gdb
gdb
是一个命令行版本的调试工具,相比于VS
等的调试器没有图形界面,无法直观的获取变量值得变化与压栈情况,所以是没有那么容易入手的
这个调试工具相比于VC、z的优点是具有修复网络断点以及恢复链接等功能,比BCB的图形化调试器有更强大的功能。
所谓“寸有所长,尺有所短”就是这个道理
在Visual Studio
中调试的核心思想在gdb
中也适用:
- 打断点
F5
继续执行
这样的按下快捷方式的调试方式与gdc
是有些不同的,gdb
是通过许多指令(命令行)来完成调试的。以下演示开始:
- 要想进行调试,其实是针对最终的可执行程序进行调试,所以需要先进行编译
- 编写程序
我在这里举例创建一个main.c
文件,vim
进入后编写完成代码
- 输入指令,进入
gdb
界面:
gcc main.c -o main -g //Debug版本
gdb main
与Debug版本同级的还有release版本,有兴趣可以了解一下
输入完指令就进入gdb
的界面了
break + 行号/函数名
在此行或者函数首打上断点
这里我输入了break + Add函数名
,所以调试器告诉我在第8
行的Add函数
已经被打上断点了。
例如想要在代码第10行打上断点,可以缩写为b 10
那第8行到底在哪儿?
为了方便起见,给大家一个小建议,打开两个终端,放置于右边窗口
这样你就可以看着代码进行调试了,十分方便直观。
-
info break
查看当前断点
调试器显示当前只有一个我打上的断点,是位于main.c
文件的第8行的。 -
del + 断点的编号
删除已有断点
断点编号就是上图Num
所对应的数字,例如所属与它的1
-
run
代码从头开始运行,触发断点就会停止,缩写为r
(输入gdb
,被调试的程序其实还未开始执行,当输入run
才真正开始执行)
由上图我们可以得知,触发了我们所打在第8行的Add
函数上的断点 -
continue
让程序继续运行,缩写为c
程序遇到断点,就会被停止下来。如果想要继续运行就输入指令continue
VS 中的
F5
相当于同时具备了run
+continue
gdb 中就将而二者分开了
-
print + 变量名
查看当前情况变量的信息,缩写为p
-
list
展示当前语句附近代码,缩写为l
笔者觉得有输入这种专门显示附近代码的指令的时间不如再打开一个终端来的直接,一劳永逸啊~ -
bt
查看当前调用栈
(例如:递归函数的调用栈)
这里bt
后显示内容说明main函数调用了Add函数。 -
next
单步执行,一次执行一行语句,缩写为n
,相当于VS中的F11
Makefile
make是一个命令工具,它解释Makefile
中的指令(应该说是规则)。
在Makefile
文件中描述了整个工程所有文件的编译顺序、编译规则。
在Makefile
中可以使用系统shell所提供的任何命令来完成想要的工作。
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
Makefile(在其它的系统上可能是另外的文件名)在绝大多数的IDE 开发环境中都在使用,已经成为一种工程的编译方法。
- Makefile文件中主要包括三个主要的部分:
1.target
目标 想要生成的可执行程序(文件、库等),相当于输出
2.dependence
依赖 (为了生成可执行文件需要用到的文件),
相当于输入,允许没有依赖。
3.conmmand
命令 具体动作,为了生成目标才去的操作
vim Makefile
编写Makefile文件,必须是这个名称!- 填写三个部分,保存退出
- 执行
make
指令进行编译,等价于make hello
- 如果make之后没有对象,默认执行第一个目标如果make之后没有对象,默认执行第一个目标
异常分析 : 输入make之后,出现遗漏分隔符错误
反复修改没有解决问题,编辑文件时gcc,rm前面使用的是Tab分隔符。
最后使用linux自带的编辑器gedit打开Makefile,将vim下的Tab键换为gedit的Tab键,得到正确结果。
总结遗漏分隔符问题解决方法:
-
gcc
、rm
之前一定要有一个tab
分隔符,不能使用空格。 -
使用
vim
编辑文件,如果配置文件vimrc
中有set expandtab(使用空格代替制表符) ,则也会出现遗漏分隔符问题。因此最好将这条语句注释,或者使用gedit
编辑器重新编辑makefile
。
注:make
也属于增量编译,如果对代码有改动,最后操作时间改变,再次执行make
指令就不会显示 xx文件 是最新的了。
-
另外在
Makefile
中添加clean
项,其中包含删除某文件语句,保存退出
执行make clean
就会进行工程清理的工作,把生成的中间文件都删除掉,只保存最纯粹的源代码。 -
小结
Makefile
还是比较经典的工程管理工具,但平常使用时不太会手写,而是运用一些工具来生成:
cmake
bazel
(中文名:火焰刀)Google出品