找个工作

C++ 编译器是怎么工作的

2021-05-05  本文已影响0人  吃掉夏天的怪物

小零碎的东西

cin.get()

文件-->可执行文件

#include <iostream>

1、预处理语句,会在编译文件之前被评估。将iostream文件里的所有内容拷贝

到这个文件里

2、文件编译,代码转为实际的机器码

x86 就是定位于32位的windows

所有.cpp文件都会被编译,而头文件则不会

记住header file 通过预处理被include到cpp文件里,那是它们被编译的时候

每个cpp文件会被编译成一个object文件,扩展名的话,用windows编译器是.obj

当我们有了一个个obj文件,也就是cpp文件被编译后的结果,我们就有办法把他们联系起来组成一个exe,这时候就是linker(连接器)的用武之处了

error list

error list 的工作原理其实是,解析(parse)output窗口,找error关键字,然后从那找信息,放入list

编译器是怎么工作的

我们用文本来写C++,就是text而已,我们需要某种方法将文本转化成应用,从而在计算机运行。从text到可执行binary,基本上有两个主要操作需要发生。一个是compoling(编译),一个是linking(连接)。

C++编译器唯一要做的就是把文本变为中继格式——obj。然后obj们会传入linker,linker会做所有linking的事。

在compiler产出这些obj时,其实它有做好几件事。首先,它需要pre-process(预处理)我们的代码,也就是所有Preprocessor语句在那时被评估。被预处理后,我们会进入tokenizing(标记解释)和parsing(解析)阶段。基本就是把这C++文本处理成编译器能懂和处理的语言。基本上结果就是创建了某种叫做abstract syntax tree(抽象语法树),也就是代码的表达,但是是以抽象语法树的形式。

说到底编译器的工作也就是把代码转化成要么是constant data(常数资料)要么是instruction(指令)。

当编译器创建了这颗语法树之后,就可以开始产生代码了,这个代码是真正的cpu会执行的代码。同时,我们也会得到一些其他数据,比如某个地方存储着我们所有的constant variables(常数变量)。这基本就是编译器的工作了,并不非复杂。

编译器给每个cpp,也就是每个translation unit生成了obj。项目里的每个cpp,都会被编译器编译成一个obj,这些cpp文件也叫translation unit(编译单元)。

本质上你得意识到c++根本不在乎文件,文件这种东西在c++里不存在。
举例说,java里,你的class名必须跟文件名相同,而你的文件夹架构也得跟package一样。之所以如此是因为java需要某些文件存在,c++完全不是这回事。没有文件这种东西,文件知识用来给编译器提供源码的某种方法。你要告诉编译器文件类型和编译器该如何处理它。(.cpp .c .h)

文件不代表任何东西。我们传给编译器每个c++文件,我们告诉它这是c++,请按c++编译。它就会把它当成一个translation unit,然后ranslation unit会得到一个obj。

在cpp文件include其它cpp有时候其实是很常见的作法,然后你只编译那一个cpp文件,也就是只有一个translation unit,也就只有一个obj。

这也就是为什么会有translation unit,cpp两个术语

pre-processing

编译第一阶段 preprocessing,在这期间,编译器就是检查所有的pre-processing语句并评估。常见的有include,define,if和ifdef。它们同样也是pragma语句,就是告诉编译器具体要做什么。

#include:你只要指定你要include哪个文件,然后preprocessor会打开文件,读取所有内容,然后黏贴进你写的include的哪个文档。

inlcude例子.png

让编译器输出一个文档,里面包含所有这些preprocessor评估的结果 .i文件
g++ -c -E

define:就是会去搜索这个词,然后替换成后面的东西。

if:让我们依据特定条件包含或者剔除代码

当preprocessor结束后,我们就可以将C++代码编译成机器码了。obj可读一点的格式,asm

DEBUG

debug是不会做任何优化的,而且会有很多额外的东西,以确保我们的代码尽可能冗长以及尽可能易于debug

常数折叠

constant folding ,任何常量都可以在编译时计算出来。

函数签名

需要独一无二的定义你的函数。当我们有多个obj,我们的函数会在多个obj中被定义。linker会负责将他们联系起来,它怎么做呢,就是会查找这个函数签名。

Call指令

当你调用函数时,编译器就会生成一个call指令

上一篇下一篇

猜你喜欢

热点阅读