GCC使用 C程序的编译过程

一、GCC是什么

链接: 参考cnblog作者面具下的戏命师.

GCC(GUN Complier Collection)是由GNU开发的编程语言编译器,GCC最初代表"GNU C Complier", 当时只支持C语言。后来又扩展能够支持更多的编程语言,包括C++,Fortran和Java等。因此,GCC也被重新定义为"GNU Complier Collection",成为历史书上最优秀的编译器,其执行效率与一般的编译器相比平均效率要高20%~30%。
GCC的官网地址为:https://gcc.gnu.org/,在Ubuntu系统下系统默认已经安装好GCC编译器。

本次在Windows平台上编译C程序使用的是DevC++,与GCC关系为,GCC是一套编译器集合。 DevC++是windows上的一个IDE,GCC是DevC++默认使用的编译器

C或C++程序从源代码生成可执行程序的过程,需要经历四个过程,分别是预处理、编译、汇编和链接。
使用GCC也要经历着四个过程,但是考虑实际过程中用户需要快速得到最终的可执行程序,因此gcc和g++都对此需求做了支持。可以一步生成可执行程序

快速生成可执行程序

C语言 汇编语言 机器语言

在这里插入图片描述

比如用gcc编译c程序可以用# gcc xxx.c实现,快速生成可执行程序
在这里插入图片描述

在这里插入图片描述
注意,虽然我们仅编写了一条 gcc 或者 g++ 指令,但其底层依据是按照预处理、编译、汇编、链接的过程将 C 、C++ 程序转变为可执行程序的。而本应在预处理阶段、编译阶段、汇编阶段生成的中间文件,此执行方式默认是不会生成的,只会生成最终的 a.out 可执行文件(除非为 gcc 或者 g++ 额外添加 -save-temps 选项)

分四步走

  1. 预处理

通过为 gcc 指令添加 -E 选项,即可控制 GCC 编译器仅对源代码做预处理操作。预处理操作,进行头文件展开,宏定义展开、删除注释等工作。主要是处理那些源文件和头文件中以 # 开头的命令(比如 #include、#define、#ifdef 等),并删除程序中所有的注释 // 和 /* … */

在这里插入图片描述
默认情况下 gcc -E 指令只会将预处理操作的结果输出到屏幕上,并不会自动保存到某个文件。因此该指令往往会和 -o 选项连用,将结果导入到指令的文件中

  1. 编译

编译是整个程序构建的核心部分,也是最复杂的部分之一。所谓编译,简单理解就是将预处理得到的程序代码,经过一系列的词法分析、语法分析、语义分析以及优化,加工为当前机器支持的汇编代码。通过给 gcc 指令添加 -S(注意是大写)选项,即可令 GCC 编译器仅将指定文件加工至编译阶段,并生成对应的汇编代码文件:

在这里插入图片描述
需要注意的是,gcc -S 指令操作的文件并非必须是经过预处理后得到的 .i 文件,-S 选项的功能是令 GCC 编译器将指定文件处理至编译阶段结束。这也就意味着,gcc -S 指令可以操作预处理后的 .i 文件,也可以操作源代码文件:

  • 如果操作对象为 .i 文件,则 GCC 编译器只需编译此文件;
  • 如果操作对象为 .c 或者 .cpp 源代码文件,则 GCC 编译器会对其进行预处理和编译这 2 步操作
  1. 汇编

汇编其实就是将汇编代码转换成可以执行的机器指令。大部分汇编语句对应一条机器指令,有的汇编语句对应多条机器指令。相对于编译操作,汇编过程会简单很多,它并没有复杂的语法,也没有语义,也不需要做指令优化,只需要根据汇编语句和机器指令的对照表一一翻译即可。汇编的作用是生成目标文件:
通过为 gcc 指令添加 -c 选项(注意是小写字母 c),即可让 GCC 编译器将指定文件加工至汇编阶段,并生成相应的目标文件。

在这里插入图片描述
需要强调的一点是,和 gcc -S 类似,gcc -c 选项并非只能用于加工 .s 文件。事实上,-c 选项只是令 GCC 编译器将指定文件加工至汇编阶段,但不执行链接操作。这也就意味着:

  • 如果指定文件为源程序文件(例如 demo.c),则 gcc -c 指令会对 demo.c 文件执行预处理、编译以及汇编这 3 步操作;
  • 如果指定文件为刚刚经过预处理后的文件(例如 demo.i),则 gcc -c 指令对 demo.i 文件执行编译和汇编这 2 步操作;
  • 如果指定文件为刚刚经过编译后的文件(例如 demo.s),则 gcc -c 指令只对 demo.s 文件执行汇编这 1 步操作。
  1. 链接

得到生成目标文件之后,接下来就可以直接使用 gcc 指令继续执行链接操作。链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

在这里插入图片描述

二、编写C程序并执行

main1.c
在这里插入图片描述

sub1.c
在这里插入图片描述

ubantu系统用gcc命令行编译main.1并运行

代码如下
gcc -c sub1.c
一条指令执行 预处理 编译 汇编三步,生成sub1.o目标文件
gcc main1.c sub1.o -o main1
编译main1.c文件为目标文件main1.o,然后链接sub1.o目标文件生成main1可执行文件
./main1
执行main1
在这里插入图片描述

Windows下用Devc++执行程序

在这里插入图片描述

三、使用Makefile高效编译程序

Makefile是什么

参考链接: csdn作者韦东山

1.为什么需要Makefile
修改源文件或头文件,只需要重新编译牵涉到的文件,
就可以重新生成 APP
2.makefile规则
一个简单的 Makefile 文件包含一系列的“规则”,其样式如下(tab键不能用空格代替):

目标(target)…: 依赖(prerequiries)…
<tab>命令(command)

注意makefile中语句执行顺序并不是从上到下
在linux下,makefile的执行实际上分为两个阶段进行
第一阶段:读取所有的makefile文件(包括“MAKEFILES”变量指定的、指示符“include”指定的、以及命令行选项“-f(–file)”指定的makefile文件),内建的变量、明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表。
第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应的规则来重建这些目标。

3.简单的例子
第 1 个 Makefile,简单粗暴,效率低:

test : main.c sub.c sub.h
gcc -o test main.c sub.c

第 2 个 Makefile,效率高,相似规则太多太啰嗦,不支持检测头文件:

test : main.o sub.o
gcc -o test main.o sub.o

main.o : main.c
gcc -c -o main.o main.c

sub.o : sub.c
gcc -c -o sub.o sub.c

clean:
rm *.o test -f

第 3 个 Makefile,效率高,精炼,不支持检测头文件:

test : main.o sub.o
gcc -o test main.o sub.o
%.o : %.c
gcc -c -o $@ $<
clean:
rm *.o test -f
1
2
3
4
5
6

Makefile实战演练

Makefile代码
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值