【发布时间】:2012-10-10 12:45:48
【问题描述】:
我试图理解 typedef 和 define 之间的区别。专门this previous question on SO有很多好帖子,但是我看不懂那个帖子
#define是一个预处理器标记:编译器本身永远不会看到它。typedef是一个编译器标记:预处理器不关心它。
谁能更详细地解释一下。我对这里的预处理器一词感到困惑。
【问题讨论】:
标签: c++
我试图理解 typedef 和 define 之间的区别。专门this previous question on SO有很多好帖子,但是我看不懂那个帖子
#define是一个预处理器标记:编译器本身永远不会看到它。typedef是一个编译器标记:预处理器不关心它。
谁能更详细地解释一下。我对这里的预处理器一词感到困惑。
【问题讨论】:
标签: c++
预处理器是在任何编译开始之前发生的阶段。它读取特定的宏和符号来替换。它通常是一到两次通过。它扫描整个源文件,并生成一个符号表来替换或扩展宏。
完成所有替换后,语法分析器接管对源文件进行词法分析、生成抽象语法树、生成代码、链接库和生成可执行文件/二进制文件。
在 C/C++/ObjC Preprocessor DIRECTIVES 中以“#”开头,后跟指令名称,例如“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。
查看An interesting preprocessor for multiple languages 和Write your own pre-processor。查看这些程序的输入和输出可以让您更深入地了解预处理器实际上是什么。
另一个小秘密:如果你有预处理器,你可以用拉丁语/德语/西班牙语编写 C :)
【讨论】:
在编译方面,您的源代码要经过很多步骤。在这些步骤中,有预处理。
预处理器是在编译器之前运行的程序,执行所有#启动的指令,如#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 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++ 预处理器是编译中很早发生的一个逻辑阶段。预处理器通过包含#include 指定的头文件的文本,通过有条件地消除部分文件(#if、#elif、#else、#endif 和变体#ifdef 和#ifndef),并通过宏替换。宏通过#define 定义;可以通过预处理器扫描源来检测宏。
预处理器消除了大多数以# 开头的行(它只留下#line 指令和它自己在#line 上的缩写变体,以告诉编译器源来自哪里)。然后,适当的编译器会看到预处理的结果并编译定义的源代码。
预处理器通常不会修改单词typedef。一个疯狂的程序员可以为typedef 定义一个宏,而预处理器可能不在乎;当定义了一个与语言中的任何关键字同名的宏时,程序员不能合法地包含任何系统头文件。否则,typedef 是编译器的问题,而不是预处理器的问题。 sizeof() 也是如此;这不是预处理器能理解的。
通常有编译器选项可让您查看预处理的输出。对于gcc,选项为-E 和-P。
【讨论】:
这意味着预处理器在编译器之前运行,它会在将源代码传递给编译器之前对其进行修改。因此,编译器永远不会看到某些代码。示例:
#define ONE 1
int x = ONE;
当你编译这个时,预处理器把它变成这个:
int x = 1;
并将新文本传递给编译器。因此,编译器看不到文本ONE。
【讨论】: