本次博客内容主要是从四个方面来说:分别是gcc,gdb,make还有makefile.
先来了解一下gcc.
在我们了解gcc之前需要先对我们日常编写的代码在编译器中的处理做出一些了解。
我们知道,日常我们用c,c++或者python等语言进行编写代码时,这些我们写的代码计算机是不认识的,计算机是只认识机器语言也就是二进制的,那么问题来了,我们该怎么让我们写的让计算机也认识呢?
在平常我们在Visual studio 2019下面编写代码时,可能并没有认识到Vs 2019是一款包含了IDE(集成开发环境)的软件,Vs2019里面含有编译器和编辑器功能,编辑器和编译器经常会配合使用,程序员会使用编辑器编写源代码,并使用编译器将代码编译成可执行程序。一般来说是要经历以下四个步骤:
1.预处理:预处理就是把我们编写的代码进行头文件展开,宏替换,去注释,条件编译等等,会生成.i的文件例如:main.i。
2.编译:在编译是,会将我们的代码进行语法检查,并生成汇编代码,生成的文件后缀一般为.s,例如:main.s。
3.汇编:我们在第二步生成了汇编代码,可是汇编代码计算机也不认识,我们还要进行第三步汇编,汇编就是把汇编代码转换成为二进制的机器码,一般文件以.o,例如:main.o。
4.链接:链接就是最后一步了,平常我们会编写多个文件这些文件都有依赖关系,而且也是需要维护的,这些都是链接应该完成的事情,除此之外,在链接中还有一件事情要完成,我们需要链接来将我们自己的代码的函数调用,外部数据和库关联起来,代码和库关联很重要。
以上四步可以简单理解为把我们代码翻译为机器语言也就是二进制所需要的过程。
在对上面有一些基本了解之后,在这里简单举个例子,在我们平常写printf函数时,就会调用c语言的库,要知道语言也是有库的,一般会有一套头文件+一套库文件(libc.a,libc.so)。
现在用gcc来具体实现这四步,首先我们编写一个简单的程序.

在vim中编写一个很简单的“hello world”的代码,下面进行第一步预处理:

在shell中输入gcc -E test.c -o test.i后,可以预处理看见生成了test.i文件接着vim test.i,观看一下test.i.

可以看到经过预处理之后,右边test.i里面代码高达八百多行,含量很高。
在预处理完成之后,将test.i文件进行编译,生成汇编代码。

需要注意的是gcc的命令,gcc -S test.i,注意得是S才行,会生成test.s文件,在vim test.s后

可以看到test.s文件确实是汇编代码编写的,完成第二部后进行第三步,将test.s文件进行汇编成二进制机器码

这里用gcc命令,gcc -c test.s后看到确实生成了test.o文件,接着vim test.o
可以看见test.o文件里面都是二进制的机器码,我们是完全看不懂的,但是这个可以直接运行吗,答案当然是不行,因为还缺少最后一步那就是进行链接。
最后进行链接gcc test.o -o test,生成test可执行文件



test可以执行的文件,确实可以输出hello world。
以上就是全部的步骤后缀分别是ESc,就可以了,注意的是链接时不需要其他选项的。
对于链接还有一些其他的知识还需要整理,如下图
可以看到有lib64/libc.so.6,这分别就是表示链接的头文件和库文件,我们在链接时分为动态库和静态库,动态库的后缀时.a,静态库的后缀是.so,库的链接都和程序的成功运行有关,在这里说明一下静态链接 VS 动态链接。
动态链接:gcc默认采用的是动态链接的方式,形成可执行的程序,动态链接就是把别人写好的库拿来用,优势是体量小,轻便。
静态链接:会将库中的有关代码拷贝进自己的可执行程序中,我们称为静态链接,拷贝完成之后我们就不在需要使用任何库了,静态链接可移植性好,但是程序体量大,而且占据磁盘内存。
下面进行gdb(linux中的调试),在写gdb调试之前,同样在vim中写一个简单的程序。

下面开始使用gdb对上面那段代码进行调试

可以看到run出来的结果是5050但是不能进行调试,因为如果一个程序是可以被调试的,那么这个程序的二进制文件一定是加入了一些debug的信息,但是release没有包含调试信息,在centos中,默认情况下生成的程序是release的不可调试,那么要将mytest文件改为debug模式。

在gdb模式下输入指令L 和 L1显示代码行数并进行打断点

这里可以看见在11行的位置打下了一个断点

d 1去掉第一个断点,去掉断点是用前面的序号来删除的,这里就只剩下一个断点了。
想要进行具体变量的显示,如 i

如果想要去掉i,显示就用undisplay +序号,进行取反就好了,注意不显示也是后面跟序号。
这里最后提一下finish vs continue vs until这三个。
finish:结束当前函数
continue:直接到下一个断点,如果程序只有一个断点就直接执行完毕
until:跳转到指定行
大致了解完gdb后,了解make和makefile
首先需要明确的是make是一条命令,makefile是一个文件
在了解makefile之前,我们需要知道文件和文件的相互依赖关系,也就是会有不同的文件之间的调用,在Vs2019中文件关系是自动帮我们调好了,但是在Linux中需要我们自己调整文件关系
1.依赖关系
2.依赖方法
举个例子就是我,儿子,打钱。找到关系和方法,来达到我们形成可以执行程序的目的。值得注意的是依赖关系和依赖方法是相辅相成的,缺一不可。

第一张图clean缩进了,Makefile里面还写错了,注意细节。

没有缩进clean可以用。
上面是Makefile文件,文件第一行显示了依赖关系,mytest是依赖于mytest.c的。
文件第二行显示了依赖方法。
文件第三行.PHONY是对应的一种修饰符号,是一种伪目标的概念,这个clean伪目标可以总是被执行。

注意调用clean时需要带上make,可以看到调用clean,确实是直接把mytest文件进行了删除。
以上就是这篇博客的全部内容了。
2023年写于六一儿童节
本文详细介绍了编程过程中从源代码到可执行文件的编译过程,包括gcc的预处理、编译、汇编和链接四个步骤。同时,讨论了动态链接与静态链接的区别。接着,文章转向调试工具gdb的使用,展示了如何设置断点和查看变量。最后,讲解了make和makefile在管理项目文件依赖性和构建流程中的作用。

1325

被折叠的 条评论
为什么被折叠?



