0

I am wondering if an infinite loop of including files causes a compiler problem or a linker problem. I tried this :

/* file : try.c */
#include "try1.c"
int main(void) {}

/* file : try1.c */
#include "try.c"
int a(void) { return 0; }

The command to compile is :

gcc -Wall try.c -o try

This obviously causes a very long output (starts like this) :

try.c:5:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try.c:1:0,
                 from try1.c:1,
                 from try.c:1:
try1.c:4:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try1.c:1:0,
                 from try.c:1:
try.c:5:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try.c:1:0:
try1.c:4:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
try.c:5:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
In file included from try.c:2:0,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                 from try.c:1,
                 from try1.c:1,
                   .
                   .
                   etc...

Well, obviously there is an infinite loop here. But when does it occur ? At the compiling process or the linker one? I think you are going to tell me at the compiling process because it will define here more than one function with the same name (because of the loop), but isn't the part that unite files occur at the linker process (And then there are no compilation problem for only one file) ?

Thanks !

4

4 回答 4

5

实际上,#include- 类型语句的扩展称为“预处理”步骤。我曾经认为这些步骤都是在任何“编译”发生之前作为一个单独的步骤处理的,但是@EricPostpischil 在评论中指出(并举了一个例子来证明它)这两件事 - 预处理和编译 - 似乎发生了同时(如源文件中的行顺序所指示的那样)。换句话说,#命令(“预处理器指令”)的扩展是“在编译发生时”完成的。从这个意义上说,该错误是“编译”错误;但在我看来,说“#include由预处理器处理”。当编译器处理“预处理器步骤”时,这条线是模糊的。绝对不是链接器导致问题 - 编译器会在你到达那一步之前很久就放弃了。

作为一般评论,将#include一个.c文件放在另一个文件中并不是一个好习惯——这就是链接器的用途。为了防止“递归包含”,您经常会在.h编译器附带的文件中看到这样的结构:

#ifndef __MYINCLUDEFILE
#define __MYINCLUDEFILE
... put the body of the include file here
#endif

这确保了一个包含文件只会被包含一次,即使它是从多个地方调用的(第一次包含时,__MYINCLUDEFILE将定义变量;下次包含时,将跳过整个函数体)。一旦你对每个包含文件都这样做了,你陷入的那种“递归陷阱”就不会再发生了。

正如@wildplasser 所指出的,使用_NAMEand__NAME是为语言和实现保留的——我将它用作示例,因为您会在编译器附带的头文件中看到类似的结构。当您创建自己的 .h 文件时,您必须考虑另一种创建唯一标识符的约定。

于 2013-08-09T14:11:03.427 回答
2

每个以“#”开头的“东西”都由预处理器处理。这就是为什么包含守卫也以“#”开头的原因。必须同时处理。

于 2013-08-09T14:19:02.050 回答
2

这是已经失败的预处理。为了演示,预处理源

gcc -E try.c

并看到它失败。

于 2013-08-09T14:24:01.567 回答
2

代码更改的各个阶段。

包含在预处理阶段扩展。因此,当您尝试进行无限循环时,实际上只有在任何编译或链接发生之​​前的预处理阶段才会出现错误。

于 2013-08-09T14:16:59.040 回答