我试图了解 typedef 和 define 之间的区别。有很多好帖子,特别是关于 SO 的上一个问题,但是我不明白那个帖子
#define
是一个预处理器标记:编译器本身永远不会看到它。
typedef
是编译器标记:预处理器不关心它。
谁能更详细地解释一下。我对这里的预处理器一词感到困惑。
我试图了解 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
}
如果 atypedef
是一个简单的文本替换机制(就像预处理器一样),那么它会起作用,但它是不允许的并且将无法编译。
预处理器是在任何编译开始之前发生的阶段。它读取特定的宏和符号来替换。它通常是一到两次通过。它扫描整个源文件,并生成一个符号表来替换或扩展宏。
完成所有替换后,语法分析器接管对源文件进行词法分析、生成抽象语法树、生成代码、链接库和生成可执行文件/二进制文件。
在 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 所著的“The C Programming Language”第 2 版一书中有一个示例,其中展示了如何创建自己的 PREPROCESSOR 以及它是如何工作的。Plan9 C 编译器也将两个过程(编译和预处理)分开。允许您在其中使用自己的 PREPROCESSOR。
查看适用于多种语言的有趣预处理器和编写您自己的预处理器。查看这些程序的输入和输出可以让您更深入地了解预处理器实际上是什么。
另一个小秘密:如果你有预处理器,你可以用拉丁语/德语/西班牙语编写 C :)
C 和 C++ 预处理器是编译中很早发生的一个逻辑阶段。预处理器通过包含由 指定的头文件的文本#include
、通过有条件地消除部分文件(#if
、#elif
、#else
、#endif
和变体#ifdef
和#ifndef
)以及通过执行宏替换来将源文件转换为翻译单元。宏是通过定义的#define
;可以通过预处理器扫描源来检测宏。
预处理器消除了大多数以开头的行#
(它只留下#line
指令和它自己的缩写变体,#line
以告诉编译器源来自哪里)。然后正确的编译器看到预处理的结果并编译定义的源代码。
预处理器通常不会修改这个词typedef
。一个疯狂的程序员可以定义一个宏,typedef
而预处理器可能不在乎;当定义了一个与语言中的任何关键字同名的宏时,程序员不能合法地包含任何系统头文件。但是,否则typedef
对于编译器来说是一个问题,而不是预处理器。所以,也是sizeof()
;这不是预处理器理解的东西。
通常有编译器选项可让您查看预处理的输出。对于gcc
,选项是-E
和-P
。
在编译方面,您的源代码要经过很多步骤。在这些步骤中,有预处理。
预处理器是在编译器之前运行的程序,并执行所有#
启动的指令,如#include
,#define
等。
在您的特定情况下,#define WORD newword
是一个指令,它说:“用新词替换所有出现的 WORD”,甚至在尝试编译程序之前。
如果您想查看它的运行情况,请尝试运行cpp file.c
并检查输出以了解它的作用。
文件.c
#define WORD "newword"
int main()
{
printf("this is word: %s\n", WORD);
return 0;
}
cpp运行后会变成
int main()
{
printf("this is word: %s\n", "newword");
return 0;
}
另一方面,typedef 用于表示“如果我谈论Type
,请理解我的意思struct more_complex_type
”,它在编译时使用,并且在cpp
传递前后保持不变。
预处理器是在编译器编译代码之前执行的“引擎”。
#define #include
是预处理器指令或宏,因此预处理器引擎执行与指令相关的代码。预处理器完成后,编译器看不到任何指令/宏。但是,编译器可以理解诸如typedef
,等结构。if
while
这意味着预处理器在编译器之前运行,并在将源代码传递给编译器之前对其进行修改。因此,编译器永远不会看到某些代码。例子:
#define ONE 1
int x = ONE;
当您编译它时,预处理器将其更改为:
int x = 1;
并将该新文本传递给编译器。因此,编译器看不到文本ONE
。