典型的C++编译器处理什么工作?

Jas*_*son 6 c++ compiler-construction linker machine-translation

在研究了编译器及其工作原理后,我了解到该过程通常分为4个步骤:预处理器,编译器,汇编器和链接器.我设想这些步骤的方式是每个人都有自己独立的程序; 预处理程序,编译程序,汇编程序和链接程序.但是,您了解到有时创建汇编代码和生成目标文件的过程全部由编译器程序处理,有时则不处理.它似乎很大程度上取决于所使用的上下文和编程语言.我的问题是,如何将C++源代码转换为机器代码的典型翻译过程如何?

  1. 预处理器是否与编译器分开?或者该过程通常是编译器程序的一部分?
  2. 编译器通常负责什么?生成汇编代码然后转换为机器代码?
  3. 链接器是否是在编译器完成后运行的独立程序?

旁注:我的问题与其他C++编译器线程不同,因为我不仅询问编译器如何工作,而且如果某些其他进程(如链接)存在自己的可执行程序,或者它们通常内置于编译器程序中.

Mat*_*son 4

所有现代编译器(至少是 gcc 和 clang,但我怀疑其他编译器有很大不同)都将预处理和编译器作为一个可执行文件。这主要是因为编译器希望能够生成良好的错误消息[指向正确的行和列,当涉及宏时,可以说“从宏 FOO(x) 调用”],并理解“我们调用了什么文件”当编译器有实际的源代码来查看时,“re in”会更容易,而不是预处理的代码。

链接器通常是一个单独的程序,而汇编器仅用于内联汇编代码[通常作为编译器的集成部分] - 否则,编译器将直接生成机器代码而不使用汇编器[至少在LLVM中,这是我最了解的编译器]。因此,编译器会生成一个完整的目标文件。

如果您有正确的选项,链接器将被调用,但它是一个单独的可执行文件,它将目标文件与运行时库和起始代码“在 main 之前”链接在一起(全局对象构造,以及类似的,以及“准备调用 main”)。这将生成可执行文件。

使用其他选项,编译器将仅生成一个目标文件,或以符号形式生成的机器代码的反汇编(选项-S)。

编译器的后端部分负责代码生成,通常还处理优化和各种代码转换以帮助优化阶段 - 例如,Clang + LLVM 将生成“统一”循环,无论您是否使用whileforgoto制作一个循环。

这有助于更高级的阶段不必识别许多不同形式的循环,并且允许编译器生成“好的”代码,无论程序员如何形成循环。[当然,如果你让它足够复杂,编译器可能不会完全弄清楚你的循环是如何工作的,并且不会很好地优化,但是对于基本形式之间的直接转换,它会执行相同的最终代码生成,无论来源的样子]。