首页 > 其他分享 >什么是编译器?

什么是编译器?

时间:2022-09-04 10:56:30浏览次数:94  
标签:文件 什么 编译器 源代码 my 链接 math

什么是编译器?

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
From: https://www.cnblogs.com/amboke/p/16654518.html

相关文章