gcc编译器眼中的C语言

编程语言一般分为编译期、运行期
有的编程语言是编译期与运行期合并在一起的,比如Python、PHP…即解释型语言
有的则是编译期与运行期分开的,比如C、C++、Java…即编译型语言

今天咱们深入聊聊编译期的C语言
运行期的C语言,我在我之前的课程中已经详细讲过,感兴趣的自己去看视频

编译期,即编译器工作的期间
一般编译器,都是基于《编译原理》实现的
在这里插入图片描述

但是C语言的编译器的实现,在《编译原理》基础上做了拓展,如图
在这里插入图片描述

接下来详细讲讲C语言编译器的各个阶段

预处理

在真正编译C语言程序之前,需要对C语言程序进行预处理,预处理是由集成在编译器中的预处理器完成的

从《编译原理》的角度,词法分析是编译器的第一个阶段。但是从C语言编译器的角度,预处理是第一个阶段

预处理阶段主要完成四件事:删除注释、宏展开、文件包含、条件编译

如果你要做实验论证,gcc -E即可实现,比如
在这里插入图片描述

举个例子吧:删除注释、宏展开,比如代码
在这里插入图片描述

预处理以后,注释没有了,宏展开了。C语言的预处理器,就是简单的宏替换
在这里插入图片描述

你会发现,预处理器会在开头多生成点东西,这些东西是什么呢?有什么用呢?

这些看似神秘的 # 开头的行,实际上叫做行控制信息(line control directives),是 GCC 预处理器在输出中自动插入的特殊指令,是方便后续编译器、调试器、诊断工具理解源码位置的信息

词法分析

经过预处理后,得到的就是完整的C语言程序了,就可以开始编译了。词法分析器启动…

词法分析器的职责是:输入源程序,输出token
在这里插入图片描述

来看看上面的程序生成的token
在这里插入图片描述

如何查看C语言程序生成的token呢?
在这里插入图片描述

你可能想问:为什么用clang,而不是用gcc?因为gcc作为老牌的编译器,不支持这个功能

来看看词法分析器生成token的过程
在这里插入图片描述

如果你想透彻理解词法分析的底层原理,你可以使用词法分析工具flex生成词法分析器,去实战。或者自己从零写一个词法分析器,体会将程序的点点滴滴转成token的过程,你的困惑就解开了…(这部分内容,我做的课程手写编程语言中有教,感兴趣的可以咨询班主任jvm-anan

语法分析

拿到源程序对应的token,就可以去做语法分析了。语法分析器启动…

语法分析器的职责是:输入token,输出抽象语法树AST。后面的阶段,都是围绕AST进行的
在这里插入图片描述

换个程序,来看看经过语法分析生成的抽象语法树
在这里插入图片描述

对应的AST
在这里插入图片描述

如何查看呢?两种方式
在这里插入图片描述

其实gcc也可以,就是生成的文件太多,看起来不直观
在这里插入图片描述

会生成这些文件
在这里插入图片描述

来看看token生成AST的过程,比如print语句
在这里插入图片描述

如果你想透彻理解语法分析的底层原理,你可以使用语法分析工具bison生成语法分析器,去实战。或者自己从零写一个语法分析器,体会将token转成AST的过程,你的困惑就解开了…(这部分内容,我做的课程手写编程语言中有教,感兴趣的可以咨询班主任jvm-anan

语义分析

语义分析器的职责是:输入AST,输出AST + 符号表
在这里插入图片描述

比如程序生成的AST长这样
在这里插入图片描述

语义分析器会遍历AST,生成符号表。这个无法查看,你可以大概理解成是这样
在这里插入图片描述

然后是在AST表中加上注解
在这里插入图片描述

语义分析是一种什么感觉呢?就像拿着一棵语法树边走边做笔记,遇到变量声明就记下来(符号表),遇到变量使用就去查阅笔记,发现有问题就报错

语义分析具体做哪些事情呢?我们所知的如:类型检查、类型转换、生命周期检查、控制流检查、访问权限…完整的如图
在这里插入图片描述
在这里插入图片描述

语义分析是编译器前端中逻辑最复杂、实现难度最高、语言标准依赖最强、对整体编译正确性最关键的阶段。我在我的课程手写编程语言中,做了初步的语义分析,我觉得让大家touch到那个感觉即可

中间代码生成
万事俱备,可以生成中间代码了。比如程序
在这里插入图片描述

生成的中间代码长这样
在这里插入图片描述

如何查看的呢?
在这里插入图片描述

前面说了,这样干会生成很多文件,后缀名是.gimple的才是

C语言的中间代码(IR)称为:GIMPLE, 三地址码形式

优化

在编译之前,还要做一件事:优化。我们使用gcc -O配置优化级别,就是在这个阶段完成的

gcc一共提供了5个优化
在这里插入图片描述

所有的优化任务
在这里插入图片描述

举个例子帮助大家理解编译优化,比如常量折叠,优化前
在这里插入图片描述

优化后
在这里插入图片描述

看到这,是不是有一种悟的感觉了…

代码生成

代码生成阶段是由代码生成器完成的。代码生成器的职责是:将优化后的中间表示(IR)转换为目标平台的汇编代码
在这里插入图片描述

比如代码
在这里插入图片描述

生成汇编代码
在这里插入图片描述

如果你想查看C语言程序生成的汇编程序,运行时查看反汇编即可,编译时呢?这样查看
在这里插入图片描述

这就是C语言代码生成的all

汇编

这个阶段就是将汇编代码编译成机器码
在这里插入图片描述

注意,这时候还不是可执行文件,是目标文件.o
在这里插入图片描述

如何得到目标文件呢?gcc -c test.s -o test.o
在这里插入图片描述

理解这个阶段非常重要,因为我们写很多底层程序,比如操作系统,需要使用汇编+C语言,就是将汇编程序编译成目标文件,C语言程序编译成目标文件,然后链接成可执行文件,才得到真正的操作系统代码

链接

万事俱备,只欠可执行文件了。链接器启动…
在这里插入图片描述

执行链接操作:gcc test.o -o test即可生成可执行文件
在这里插入图片描述

如果有多个中间文件,可以将多个中间文件链接:gcc test.o 1.o 2.o -o test

注意,gcc完成链接工作,背后其实是调用链接器ld实现的

以上就是C语言程序编译期的全部,你学废了吗?

后续还会更新更多超硬核文章,感兴趣的话可以关注**【硬核子牙】**微信公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值