编译器中的预处理到底是什么意思

What does preprocessing exactly mean in compiler

本文关键字:是什么 意思 预处理 编译器      更新时间:2023-10-16

我试图理解typedef和define之间的区别。有很多很好的帖子,特别是在前面关于SO的问题中,但是我无法理解该帖子

#define是一个预处理器令牌:编译器本身永远不会看到它。
typedef是一个编译器令牌:预处理器不关心它。

谁能更详细地解释一下。我对这里的术语预处理器感到困惑。

预处理器是在编译器之前运行的程序,本质上执行文本替换。 当你写:

#define X 10
int main() 
{
int x = X;
}

预处理器将该文件作为输入,做它的事情,然后输出:

int main() 
{
int x = 10;
}

然后编译器对预处理的输出执行其操作。

另一方面,typedef是编译器理解的结构。 当你写:

typedef unsigned int uint_32;

编译器知道uint32实际上是unsigned int的别名。 此别名由编译器本身处理,涉及的逻辑比简单的文本替换多一些。 通过一个简单的例子,这一点变得很明显:

typedef int my_int;
int main()
{
unsigned my_int x;  // oops, error
}

如果typedef是一个简单的文本替换机制(就像预处理器一样),那么这将起作用,但它是不允许的,并且将无法编译。

预处理器是在任何编译开始之前发生的阶段。它读取要替换的特定宏和符号。它通常通过一到两次。它扫描整个源文件,并生成符号表以替换或扩展宏。

完成所有替换后,语法分析器将接管源文件的词法分析、生成抽象语法树、生成代码、链接库和生成可执行文件/二进制文件。

在 C/C++/ObjC 预处理器中,指令以"#"开头,后跟指令名称,如"define"、"ifdef"、"ifndef"、"elif"、"if"、"endif"等。

预处理前:

#define TEXT_MACRO(x) L##x
#define RETURN return(0)   
int main(int argc, char *argv[])
{
static wchar_t buffer[] = TEXT_MACRO("HELLO WORLD");
RETURN ;
}

预处理后:

int main(int argc, char *argv[])
{
static wchar_t buffer[] = L"HELLO WORLD";
return (0);
}

如果我没记错的话,Kernighan和Ritchie的《C编程语言》第2版一书有一个例子,他们展示了如何创建自己的预处理器以及它是如何工作的。此外,Plan9 C编译器将两个过程(编译和预处理)分开。允许您在其中使用自己的预处理器。

查看一个有趣的多种语言预处理器和编写自己的预处理器。查看这些程序的输入和输出可以让您更深入地了解预处理器的实际含义。

另一个小秘密:如果你有一个预处理器:),你可以用拉丁语/德语/西班牙语编写 C 代码

C 和 C++ 预处理器是编译中很早就发生的逻辑阶段。 预处理器通过包含由#include指定的头文件的文本、有条件地消除文件的某些部分(#if#elif#else#endif和变体#ifdef#ifndef)以及执行宏替换,将源文件转换为翻译单元。 宏通过#define定义;宏可以通过扫描源的预处理器来检测。

预处理器消除了大多数以#开头的行(它只留下#line指令和自己的缩写变体,#line后面告诉编译器源来自哪里)。 然后,编译器本身会看到预处理的结果并编译定义的源代码。

预处理器通常不会修改单词typedef。 一个疯狂的程序员可以为typedef定义一个宏,而预处理器可能不在乎;程序员无法合法地包含任何系统标头,而存在与语言中的任何关键字同名定义的宏。 但是,否则,typedef是编译器的问题,而不是预处理器的问题。sizeof()也是如此;这不是预处理器理解的。

通常有一些编译器选项允许您查看预处理的输出。 对于gcc,选项是-E-P

预处理器是在编译器编译代码之前执行的"引擎"。#define #include是预处理器指令或宏,因此预处理器引擎执行与指令相关的代码。预处理器完成后,编译器看不到任何指令/宏。 然而构造如typedefifwhile等。被编译器理解。

在编译方面,您的源代码会经过很多步骤。在这些步骤中,有预处理。

预处理器是在编译器之前运行的程序,并执行所有#启动的指令,如#include#define等。

在您的特定情况下,#define WORD newword是一个指令,上面写着:"将所有出现的 WORD 替换为新词",甚至在尝试编译程序之前。

如果要查看它的实际效果,请尝试运行cpp file.c并检查输出以了解其功能。

文件.c

#define WORD "newword"
int main()
{
printf("this is word: %sn", WORD);
return 0;                           
}

将在 CPP 运行后成为

int main()
{
printf("this is word: %sn", "newword");
return 0;
}

另一方面,typedef 用于说"如果我谈论Type,请理解我的意思是struct more_complex_type"它在编译时使用,并且在cpp传递前后将保持不变。

这意味着预处理器在编译器之前运行,并在将源代码传递给编译器之前对其进行修改。因此,编译器永远不会看到某些代码。例:

#define ONE 1
int x = ONE;

编译时,预处理器将其更改为:

int x = 1;

并将该新文本传递给编译器。因此,编译器看不到文本ONE