通过历史 --> 了解翻译环境(预处理、编译、汇编、链接)

前言

        这是我们学习代码的最重要的一个知识点之一,因为我们要去运行一个代码并不是简单的去直接出结果,而是经过了很多我们看不到的步骤,我们在这里以C语言为例子在Linux的环境下讲解,大家没有学过Linux的不用担心,最后会有一个思维导图,直接看就行。

一、了解编译器和语言的历史

        大家可以先思考一下这样一个问题:是先有语言还是先有的编译器呢?

其实在我们计算机刚刚诞生的时候,是没有编程语言的,更没有编译器,人们早先是靠打孔纸带给计算机传输命令的,但是这样实在是太麻烦了,非常影响效率,所以这时候有人就想了,能不能发明一种语言来和我们的计算机沟通呢?其实在这个时期有很多的语言萌芽了,但是这里以汇编语言为准,在汇编语言发明出来之后,人们还是觉得麻烦,就又发明了C语言,那C语言是如何跟计算机沟通的呢?肯定不能是C语言的那些代码,大家也知道,要通过编译器来翻译,但是是先有的C语言?还是先有的编译器呢?

        答案很明显了,一定是先有的语言,那给C语言翻译的编译器是什么语言写的呢?因为大家要知道这样的问题,当一个语言发明出来之后,编译器一定不是这个语言写的,因为这个语言根本不知道正确性,所以无法写出一个编译器,所以基于这样的原因,第一个C语言的编译器是汇编语言写的,那是直接把C语言翻译成二进制指令吗?我们要知道站在巨人的肩膀上,因为汇编语言和C语言很相似,汇编语言还有它自己的编译器翻译成二进制指令,所以我们只需要将C语言翻译成汇编语言就OK了。这也是为什么我们在翻译环境要有汇编这一步骤。既然大家知道C语言的第一个编译器是汇编语言写的,那汇编语言的第一个编译器就是二进制指令写的。

        但是编译器是存在不断的自我更新的,也就是说,我们的C语言可以通过编译器来判断正确性和合理性了,我们就可以用C语言来写自己的编译器了,不断的更新迭代,才有了现在这么优秀的编译器,讲到这里,我们就正式开始学习我们的翻译环境吧!

二、总体步骤

1. 翻译环境:在这个环境中,源代码会被翻译成机器可以读懂的二进制指令

2. 执行环境:实际执行代码

三、翻译环境

翻译环境从整体角度就是执行了下面的事情:

1. 源文件经过编译器生成对应的目标文件

2. 链接库和目标文件通过链接器生成对应的可执行程序

3. 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

四、具体化的翻译环境

五、解读翻译环境

1 预处理阶段(形成.i文件)

如图所示,预处理主要是处理我们的头文件,注释和预处理指令,条件编译这些;

我们可以使用下面的指令来观察现象:

 gcc -E test.c > test.i

预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。

下面就是操作之后的图:

预处理阶段的test.i
头文件被展开,展开后又700多行
注释被删除
预处理指令被替换

关于预处理指令可以看我的这篇博客:http://t.csdnimg.cn/Cl0OI

2 编译阶段(形成.s文件)

在这一步就是把C代码翻译成汇编指令,可以检查我们的语法,词法和语义。通常的编译错误就是我们的语法,词法或者语义出现了错误;

在编译阶段中我们也有相应的指令:

gcc -S test.c

编译完成之后就停下来,结果保存在test.s中。下面就是操作之后的图:

符号汇总就是将我们的全局变量,函数等汇总到一起。

3 汇编阶段(形成.o/.obj文件)

汇编阶段是把汇编指令翻译成二进制指令,形成.o/.obj这样的目标文件,但是这个目标文件是不能执行的。

在汇编阶段的指令是:

gcc -c test.c

汇编完成之后就停下来,结果保存在test.o中。下面是操作之后的图:

因为在test.o文件里放的都是二进制指令,我们是没办法看懂的,但是里面有一个ELF我们是可以看懂的。 

因为在test.o里是按照ELF格式存储的,所以我们输入如下指令可以翻译ELF文件:

readily -a test.o

翻译之后,在汇编这里是 形成了符号表,符号表就是将符号汇总的放在一个表里,如下:

4 链接阶段(形成.exe的可执行程序)

说白了,链接就是找函数的定义

        比如说我们在main函数里调用了printf函数,在预处理阶段只是把头文件展开了,头文件只是包含了一些函数声明,并没有函数定义,所以在链接阶段会去找这个函数定义,来实现相关的功能;

        在这里其实我们去调用的库文件是属于动态库的,比如stdio,stdlib,string,assert等;动态库在链接的时候是跟我们的源文件捆绑在一起实现功能的。

        而静态库就是把里面的内容拷贝一份放在源文件中。

在多文件的时候,可以将多文件的符号表给合并到一起,因为我们每个.c文件都会经过编译,所以在最后链接到时候,链接就像一捆绳子,将很多个.c文件整合在一起。

合并段表:将多文件合并

合并符号表:合并多文件里的函数的定义和声明,各个符号表放在一起。

在这里的错误通常是链接失败,原因就是你在多文件中,某个函数没有定义,符号表里没有这个函数

六、执行

执行没啥说的,编译链接通过了,执行就没啥讲的了;

给大家一个指令来执行c语言的文件吧

//编译
gcc test.c
//编译通过生成a.out文件,再执行
./a,out

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 30
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

实习秋招必胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值