根据各种来源(例如,the SE radio episode with Kevlin Henney,如果我没记错的话),“带有类的C”是用预处理器技术实现的(然后将输出提供给C编译器),而C ++总是如此已经用编译器实现(刚好在早期就吐出了C)。这似乎引起了一些混乱,所以我想知道:
预处理器和编译器之间的边界究竟在哪里?你何时调用一个实现语言“预处理器”的软件,何时称它为“编译器”?
那么,“编译语言”是一个既定术语?如果是这样,究竟是什么意思?
答案 0 :(得分:8)
这是一个有趣的问题。我不知道一个明确的答案,但如果按下一个,我会说这个:
预处理器不会解析代码,而是扫描嵌入的模式并扩展它们
编译器实际上通过构建AST(抽象语法树)来解析代码,然后将其转换为不同的语言
答案 1 :(得分:4)
预处理器输出的语言是输入语言的子集。
编译器输出的语言(通常)与输入的语言非常不同(机器代码)。
答案 2 :(得分:2)
从简化的个人观点来看:
我认为预处理器是任何形式的文本操作,它没有底层语言的概念(即:语义或构造),因此只依赖于它自己的一套规则来履行其职责。
当规则和规则应用于正在处理的内容时,编译器启动(是的,它使我的预处理器成为编译器,但为什么不是:P),这包括语法和词法检查,以及包括从x(文本)到y(二进制/中间形式)的转换。正如我的一位教授所说:"它是一个有输入,流程和输出的系统"。
答案 3 :(得分:2)
C / C ++ 编译器关心类型正确性,而预处理器只是扩展符号。
答案 4 :(得分:0)
编译器由serval进程(组件)组成。预处理器只是其中之一,而且相对最简单。
来自维基百科的文章Division of compiler processes:
除了最小的编译器外,所有编译器都有两个以上的阶段。然而, 这些阶段通常被视为前端或前端的一部分 后端。这两个目标相遇的地方是开放的 辩论。
前端通常被认为是句法的地方 和语义处理,以及翻译到较低的 表示级别(比源代码)。
中间端通常是 旨在对源代码以外的表单执行优化 或机器代码。此源代码/机器代码独立性 旨在使版本之间能够共享通用优化 支持不同语言和目标处理器的编译器。
后端从中间获取输出。它可能会执行更多 特定的分析,转换和优化 电脑。然后,它为特定的处理器和操作系统生成代码。“
预处理只是前端作业的一小部分。
第一个C ++编译器是通过在现有C编译器工具集之前附加附加进程而制作的,不是因为它是好的设计,而是因为时间和资源有限。
如今,我不认为这种非原生C ++编译器能够在商业领域中存活下来。
答案 5 :(得分:0)
答案很简单。 预处理器将文本作为输入,并将文本作为输出。这方面的例子是旧的unix命令m4,cpp(C预处理器),以及像roff和nroff和troff这样的unix程序,它们用于(现在仍然)格式化手册页(unix命令“man”)或格式文本用于印刷或排版。 预处理器非常简单,他们对所处理的“文本语言”一无所知。换句话说,他们通常处理自然语言。除了名称之外的C预处理器,例如只识别#define,#include,#ifdef,#ifdef,#else等。如果你使用#define MACRO,它会尝试在它找到的任何地方“扩展”该宏。但这不需要是C或C ++程序文本,它也可以是用意大利语或希腊语写的小说。 跨编译成不同语言的编译器通常称为翻译器。因此,发布C代码的C ++旧cfront“编译器”是一个C ++转换器。 历史上使用预处理器和后来的翻译器,因为旧机器只是缺少内存以便能够在一个程序中完成所有操作,而是由专门的程序和从磁盘到磁盘完成。 典型的C程序将从各种来源编译。构建过程将使用 make 进行管理。在我们的日子里,C预处理器通常直接构建到C / C ++编译器中。典型的make运行会调用* .c文件上的CPP并将输出写入不同的目录,从那里C编译器CC将其直接编译为机器代码,或者更常见的是将汇编代码输出为文本。注意:c编译器只检查语法,它并不真正关心类型安全等。然后汇编程序将采用该汇编程序代码并输出一个* .o文件,以后可以与其他* .o文件和* .lib链接将文件转换为可执行程序。 OTOH你可能有一个不会调用C编译器的make规则,而是lint命令,C语言分析器,它正在寻找典型的错误和错误(c编译器忽略它们)。 在维基百科(或使用man的机器终端)上查找lint,nroff,troff,m4等非常有趣; D