#include实际上做了什么?

问题描述:

在C(或基于C语言),一个可以愉快地使用以下语句:#include实际上做了什么?

#include "hello.h"; 

瞧,在每hello.h函数和变量是自动地使用。

但它实际上做了什么?我浏览了编译器文档和教程,并花费了一些时间在线搜索,但我可以对神奇的#include命令形成的唯一印象是它“复制粘贴”hello.h的内容而不是该行。还有更多。

+2

如果有任何安慰,预处理器也可能插入特定于实现的注释,以便在生成调试信息时获取行号。如果它实际上具有复制粘贴的效果,则调试器将不知道“真实”源文件和行号。同样'__FILE__'和'__LINE__'必须在复制粘贴之前被替换。就程序的意义而言,虽然是复制粘贴。 – 2011-04-20 19:24:20

从逻辑上说,该复制/粘贴正是发生的情况。恐怕没有更多了。虽然你不需要;

你的具体例子是由规格所覆盖,部分6.10.2源文件包含,第3段:

形式的预处理指令

# include"Q-炭 - 序列"新生线

导致用"分隔符之间指定序列标识的源文件的全部内容替换该指令。

这(复制/粘贴)正是#include "header.h"所做的。

请注意,#include <header.h>或编译器无法找到文件"header.h"而它试图改为#include <header.h>时将会有所不同。

+1

“不同”只是因为它通常在不同的地方搜索,并与(标准)库头文件在心理上相关联。 – delnan 2011-04-20 19:13:18

+0

@delnan,根据规范,它们不必有所不同 - 所有搜索都以“实现定义”的方式执行。不同之处在于''''表格如果不起作用,就会回到''表格。 @ pmg是完全正确的。 – 2011-04-20 19:15:43

+0

也是“不同的”,因为当您执行'#include '时,不需要有一个名为'“thing.h”'的文件。 – pmg 2011-04-20 19:17:29

不是,没有。编译器将原始文件描述符保存在堆栈上并打开d文件;当它到达该文件的末尾时,它将关闭它并弹出回原始文件描述符。这样,它可以几乎任意地嵌入d文件。

+1

编译器在gcc中传递例如对#include一无所知,因为它是预处理器传递。 – fazo 2011-04-20 19:36:49

+0

@fazo:在大多数情况下,这种区别是没有意义的。如果你出于某种原因需要学习,我可以去找一个不完整的编译器列表,以及他们是否使用预处理器。 – geekosaur 2011-04-20 19:38:30

它是预处理器的一部分。看看http://en.wikipedia.org/wiki/C_preprocessor#Including_files。是的,它只是复制和粘贴。

这是一个很好的链接来回答这个问题。

http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx

通常的#include和#包括“路径名”只是在不同的搜索预处理器

的“#包括”的顺序声明“抓住注意”前的 - 处理器(在你的程序实际编译之前发生的进程)和“告诉”预处理器包含“#include”语句后的任何内容。虽然预处理器可以被告知做了很多事情,但在这个例子中,它被要求识别一个头文件(在该头的名称后面用“.h”表示,表示它是头)。现在,头文件是一个包含C声明和未在代码中明确定义的函数定义的文件。这是什么意思?那么,如果你想使用一个函数或者定义一个特殊类型的变量,并且你知道这些函数/定义是在别处定义的(比如标准库),那么你可以包含(#include)你知道包含的头文件你需要什么。否则,每次你想使用打印功能(就像你的情况),你必须重新创建打印功能。如果它没有在你的代码中明确定义,并且你没有用你正在使用的函数#include头文件,你的编译器会抱怨说:“嘿!我没有看到这个函数被定义在哪里,所以我不用'不知道在你的代码中使用这个未定义的函数是什么!“。