预编译在编译器中的确切含义是什么

时间:2012-10-19 20:37:54

标签: c++

我试图理解typedef和define之间的区别。 this previous question on SO特别有很多好帖子,但我无法理解陈述的帖子

  

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

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

6 个答案:

答案 0 :(得分:7)

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

#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是一个简单的文本替换机制(就像预处理器那样),那么这将起作用,但是它是不允许的,并且将无法编译。

答案 1 :(得分:5)

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

在完成所有替换之后,语法分析器接管lexing-parsing源文件,生成抽象语法树,生成代码,链接库和生成可执行文件/二进制文件。

在C / C ++ / ObjC预处理器中,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 languagesWrite your own pre-processor。查看这些程序的输入和输出可以让您更深入地了解预处理器的实际内容。

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

答案 2 :(得分:4)

C和C ++预处理器是编译中的一个逻辑阶段,很早就发生了。预处理器通过有条件地删除部分文件(#include#if,{{1},将源文件转换为翻译单元,方法是包含#elif指定的头文件的文本。 }},#else和变体#endif#ifdef),以及进行宏替换。宏通过#ifndef定义;预处理器扫描源可以检测到宏。

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

预处理器通常不会修改单词#line。疯狂的程序员可以为typedef定义一个宏,预处理器可能不关心;程序员无法合法地包含任何系统头,而有一个宏定义与该语言中的任何关键字同名。否则,typedef是编译器的问题,而不是预处理器。同样,typedef;这不是预处理器理解的东西。

通常有编译器选项可以让您查看预处理的输出。对于sizeof(),选项为gcc-E

答案 3 :(得分:2)

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

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

在您的特定情况下,#define WORD newword是一个指令,说明:“甚至在尝试编译程序之前,将所有出现的WORD替换为newword”。

如果你想看到它的实际效果,请尝试运行cpp file.c并检查输出以了解它的作用。

file.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通行证。

答案 4 :(得分:2)

预处理器是在编译器编译代码之前执行的“引擎”。 #define #include是预处理程序指令或宏,因此预处理程序引擎执行与指令相关的代码。当预处理器完成时,编译器不会看到指令/宏。 但是,编译器可以理解typedefifwhile等构造。

答案 5 :(得分:1)

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

#define ONE 1
int x = ONE;

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

int x = 1;

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