什么是编译器?
作者:互联网
什么是编译器?
Compile Errors
如果您曾经接触过编程或编码,那么您很可能听说过编译器。特别是当您尝试构建从 GitHub 获得的 C/C++ 项目时,它们会出现丑陋的链接和编译器错误。我知道看到它们很烦人,但是,它们都意味着什么。今天我将告诉你关于编译器的最基本的事情,以便你更好地理解它们错误的原因。我将尝试一些问题,例如:它们为什么存在?他们解决了什么问题?它们是如何工作的?等等
本文仅作为介绍。有比我更聪明的冠军。如果您正在寻找更高级的文章,请查看它们。 YouTuber ' 切尔诺 ’就是一个很好的例子。我从他那里学到了大部分技能和知识。
此外,我不会谈论编译器阶段,如语法或词法分析。相反,我将专注于可能对您的项目有所帮助的事情。我希望它能让你更好地理解什么是编译器。
什么是编译器?
如果我要以 ELI5 的形式解释编译器,它会是这样的:
编译器将您的代码转换为机器可以理解的语言。
编译器基本上是一个“小”程序,它将人类可读的源代码转换为 CPU 可以理解和执行的指令集。源代码可以是 C、C++、Fortran、Rust、Swift 等。机器码实际上是汇编代码。所以我们可以说,编译器创建/产生汇编代码。
Two Most Popular Compilers — Gcc and Clang (LLVM)
一些流行的编译器/工具包是:GCC、Clang、MSVC、英特尔 C/C++ 编译器。他们都有优点和缺点。例如;与其他编译器相比,英特尔的编译器非常擅长算术运算,Clang 提供比 GCC 更好的错误输出等。
它们为什么存在?
我们, 作为人类 , 用文字互相交流。另一方面,计算机使用 1 和 0。如果我们想与他们交谈(通过给出指示),我们需要一个“翻译”。这个翻译器需要将我们使用拉丁字母的单词转换成一堆 1 和 0。
这里我们介绍编译器。他们是我们需要的翻译人员。当然,我们不能只告诉编译器:“嘿,在屏幕上画一个三角形!”我们需要用更正式的语言交谈。我们称这些语言为“编程语言”,如 C++ 或 Rust。
长话短说,编译器存在的原因是我们之间的语言差异, 人类 ,和机器。
An Example C Code — Source: unplash.com Authort: Krishna Pandey
它们是如何工作的?
编译器不能只通过逐行阅读来翻译源代码。它需要一些抽象并分阶段工作。有两个主要阶段:编译和链接。它们是编译器需要做的最基本的任务。
Simplified Stages and Corresponding Files
为了解释每个“阶段”的作用,我编写了一个简单的 C++ 代码,它只需减去两个数字并将结果打印到屏幕上。有三个源文件: 主文件
, my_math.hpp
和 我的数学.cpp
.基本上, 我的数学
文件是我的课程和定义编写的地方 主要的
是程序的入口点。被包围的文件 虚线正方形 是优化的汇编文件。别担心,我稍后会解释。
Source Code
编译
在编译阶段,整个源代码被分析、预处理、优化并转换为目标代码(s 图片中的第 1 到 4 个标签 )。这是所有“翻译”发生的阶段。当您收到编译错误时,它会发生在阶段。您可以通过简单地调用来编译 C++ 克++
, 铿锵++
或类似的编译器。这是一个例子:
铿锵++ main.cpp
默认情况下,编译器会“删除”中间文件并立即为您提供可执行文件。如果您想查看这些中间文件,您需要指定一些参数。
预处理
编译器做的第一件事是“处理”您使用“预处理器”标签指定的所有代码。例如, #包括,
#定义,
和 #ifndef。
编译器基本上只是查找所有符号 #
并处理它们。在您获得一个 。一世
文件。该文件仍然是人类可读的源代码。
Pre-Processed main.cpp
什么时候我们 #包括
iostream,它的所有函数和定义都将包含在我们的源代码中,因此得名 包括 .虽然我的源代码很小,但预处理后的文件要大得多。从 14 到 45762 行代码!它基本上做了一个复制粘贴。
您可以使用 -E 标签获取预处理文件:
clang++ -E main.cpp > main.i
集会
现在我们有了最终的预处理源代码,编译器可以开始翻译了。在我们的例子中,C++ 源代码首先被翻译成汇编语言。汇编仍然是人类可读的代码。它有类似的操作 移动
, 添加
和 子
.这些操作对应不同的 CPU 指令。它们从字面上指定了 CPU 应该做什么!
Assembly Code of my_math.cpp
您可以使用 -S 标签获取汇编代码:
clang++ -S my_math.cpp -o my_math.s
这里有趣的部分是我们的源代码只做减法,但汇编代码似乎做了更多的事情。调用许多操作,例如 字符串
, ldr
和 ret
.那些是什么?
编译器会执行这些额外的操作以进行更好的调试等。幸运的是,创造编译器的聪明人也创造了一种叫做 编译器优化 .他们分析您的来源并尝试通过减少装配操作来“优化”它。因此,使您的代码更快。
Compiler Optimizations Turned On
您可以看到它“优化”我的代码的效果如何。太疯狂了!编译器优化具有不同的级别,例如 o1
, o2
和 o3
. O3 是最激进的,可以生成最快和最优化的代码。您可以启用优化并使用 -O 标记指定级别:
clang++ -S -O2 my_math.cpp -o my_math_opt.s
目标文件
你问什么是目标文件?它们就是我们之前提到的 CPU 指令。它们是使用之前的汇编代码创建的。您可以打开并尝试阅读它们,但它充满了 1 和 0。目标文件不是供我们阅读的,它们是供计算机使用的。
仅供参考:Windows 使用 .obj
** __ 作为文件扩展名而不是** .o
.
每个目标文件对应一个源代码。所以我的 主文件
文件产生一个 主要的.o
文件和 我的数学.cpp
生产 my_math.o
.您可以使用 -C 标签获取目标文件:
clang++ -C main.cpp
最后,我们有两个可以被计算机读取的目标文件。但是,我们有两个不同的文件。哪一个将用于启动我们的程序?函数将如何定义 my_math.o
可用于 主要的.o
?答案在链接阶段。
链接
在链接阶段,所有目标文件都链接在一起。编译源代码时,可能有多个包含语句和外部函数调用。例如,在我们的 主文件
__ 文件中我们调用了一个函数“substract()”,该函数在 我的数学.cpp
文件。
Linking Two Object Files
现在,在编译阶段我们获得了两个目标文件。 主要的.o
和 my_math.o
.链接器的工作是链接这两个文件,以便它们可以相互“通信”。您可以将链接器视为“合并”。它基本上采用所有目标文件并将它们“合并”到一个文件中。您可以通过调用链接一个或多个文件并创建和执行:
clang++ -C main.o my_math.o -o 输出
在链接阶段之后,我们终于获得了我们的可执行文件,名为 输出
.这是计算机可以执行的文件。在 Windows 中,它具有扩展名 。可执行程序
在 Linux 中 。出去
.可执行文件包括我们所有的代码 主文件
和 我的数学.cp
感谢编译器和链接器。
最后的话
当我们回顾过去时,我们了解了编译器是如何工作的,它服务于什么目的以及它们存在的原因。编译器基本上是我们人类和计算机之间的翻译器。它们帮助我们使用编程语言进行交流。使用汇编语言和许多不同的转换/翻译,它产生机器可读的目标文件。最后,它链接这些目标文件以创建单个可执行文件。之后,我们用它来运行我们漂亮的代码。
感谢您阅读我关于编译器的文章。我知道这根本不是技术解释。这更像是对编译器的高级和实用性。如果您发现任何错误或错误,请告诉我。
保重❤
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明
本文链接:https://www.qanswer.top/12070/47520410
标签:文件,什么,编译器,源代码,my,链接,math 来源: https://www.cnblogs.com/amboke/p/16654518.html