简体   繁体   English

包含循环-链接器或编译器错误?

[英]Include loop - linker or compiler error?

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 ! 谢谢 !

Actually, the expansion of #include - type statements is called a "preprocessing" step. 实际上, #include -type语句的扩展称为“预处理”步骤。 I used to think that these steps were all handled as a separate step before any "compiling" happened, but @EricPostpischil pointed out in the comments (and gave an example to demonstrate it) that the two things - preprocessing and compiling - appear to happen concurrently (as the order of lines in the source file dictates). 我曾经以为这些步骤都是任何“编译”发生之前都作为一个单独的步骤处理的,但是@EricPostpischil在注释中指出了这一点(并给出了一个示例来演示它),这似乎发生了预处理和编译这两个过程同时(如源文件中各行的顺序所指示)。 In other words, the expansion of # commands ("preprocessor directives") is done "as compilation happens". 换句话说, #命令(“预处理程序指令”)的扩展是在“编译发生时”完成的。 In that sense, the error is a "compile" error; 从这个意义上讲,该错误是“编译”错误。 but in my mind it is valid to say "the #include gets handled by the preprocessor". 但在我看来,说“ #include由预处理器处理”是正确的。 When "preprocessor steps" are handled by the compiler, the line is blurred. 当编译器处理“预处理程序步骤”时,该行是模糊的。 It is definitely not the linker that is causing the problem - the compiler will have given up long before you get to that step. 绝对不是导致此问题的链接程序-编译器将在您执行该步骤之前就已经放弃了很长时间。

As a general comment, it is not good practice to #include one .c file in another - this is what the linker should be used for. 通常,将#include .c文件包含在另一个文件中不是一个好习惯-这是链接器应使用的目的。 And in order to prevent "recursive includes", you will often see a structure like this in the .h files that come with your compiler: 并且为了防止“递归包含”,您经常会在编译器随附的.h文件中看到类似这样的结构:

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

this ensures that an include file will only be included once, even if it's called from multiple places (the first time it's included, the __MYINCLUDEFILE variable will be defined; next time it is included, the entire body of the function is skipped). 这样可以确保即使从多个位置调用了include文件,它也只会被包含一次(第一次包含它时,将定义__MYINCLUDEFILE变量;下次包含它时,将跳过该函数的整个主体)。 Once you do this with every include file, the kind of "recursive trap" that you fell into can no longer occur. 一旦对每个包含文件都执行了此操作,就不会再出现您陷入的那种“递归陷阱”。

As was pointed out by @wildplasser, the use of _NAME and __NAME is reserved for the language and the implementation - I am using it as an example because you will see constructs like this in the header files that ship with your compiler. 正如指出的@wildplasser,使用_NAME__NAME保留的语言和实现-我使用它作为一个例子,因为你会看到这样的头文件附带编译器的构造。 When you create your own .h files you have to think of another convention that creates unique identifiers. 创建自己的.h文件时,必须考虑另一种创建唯一标识符的约定。

There are various stages at which code gets changed. 在更改代码的各个阶段。

The includes are expanded in the preprocessing stage. 包含项在预处理阶段进行了扩展。 So when you try to make an infinite loop, its actually an error at the preprocessing stage only before any compilation or linking happens. 因此,当您尝试进行无限循环时,仅在任何编译或链接发生之​​前,它在预处理阶段实际上就是一个错误。

Every "stuff" starting with "#" are handled by the preprocessor. 每个以“#”开头的“东西”都由预处理器处理。 That's why the include guard also begin with "#". 这就是为什么include防护也以“#”开头的原因。 It has to be handled at the same time. 它必须同时处理。

It's the preprocessing that already fails. 只是预处理已经失败了。 To demonstrate, preprocess the source with 为了进行演示,请使用

gcc -E try.c

and see it fail. 并看到它失败了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM