简体   繁体   English

链接阶段的#include 指令

[英]the #include directive during the linking stage

A header file usually has some safe guard using the #ifndef directives(or similar) eg:头文件通常有一些使用#ifndef指令(或类似指令)的安全保护,例如:

//header.hpp
#ifndef HEADER
#define HEADER
//code
#endif  

but, I have a confusion here, what if we do the following(consider the two file's source codes):但是,我在这里有一个困惑,如果我们执行以下操作(考虑两个文件的源代码)会怎样:

//file1.cpp
#include "header.hpp"
//somecode  

and the file和文件

//file2.cpp
#include "header.hpp"
//somecode  

if we did something like this:如果我们做这样的事情:

g++ file1.cpp file2.cpp -o mainfile  

we'd get a single executable that would get a single executable with no duplication since the includes are checked at compile time.我们会得到一个单一的可执行文件,它会得到一个没有重复的单一可执行文件,因为在编译时检查包含。

But, what if we do:但是,如果我们这样做:

g++ -c file1.cpp -o file1.o g++ -c file1.cpp -o file1.o
g++ -c file2.cpp -o file2.o g++ -c file2.cpp -o file2.o
g++ file1.o file2.o -o mainfile.o g++ file1.o file2.o -o mainfile.o

What happens during the linking stage?在链接阶段会发生什么? Will the includes have conflict?包含会有冲突吗? What happens to the includes during the compile time?在编译期间包含会发生什么? Does it get duplicated?它会被复制吗? What is the mechanism under the hood to deal with this at this stage?在这个阶段处理这个问题的机制是什么?

Normally a header file only contains function and variable declarations, and not their definitions.通常,头文件只包含函数和变量声明,而不包含它们的定义。 It's the definitions which are processed by the linking stage, so one can include a header many times in different source files and the linker just won't see anything.它是由链接阶段处理的定义,因此可以在不同的源文件中多次包含标头,而链接器将看不到任何内容。 If you do have a global function or variable definition in a header file, you will get a linker error.如果头文件中有全局函数或变量定义,则会出现链接器错误。

The formal term here is "Translation Unit".这里的正式术语是“翻译单元”。 That's what you call a single .cpp file with all the headers included by it.这就是您所说的包含所有标头的单个 .cpp 文件。 Preprocessor definitions do not span Translation Units, and you have two Translation Units here.预处理器定义不跨越翻译单元,这里有两个翻译单元。 The linking process is what combines Tranlation Units, but at that phase the preprocessor is long done.链接过程是结合翻译单元的过程,但在那个阶段,预处理器已经完成了很长时间。

Both are exactly the same.两者完全相同。 The Guard doesn't go to the next file. Guard 不会转到下一个文件。 Every file is compiled with new #define - state.每个文件都使用新的 #define - state 编译。

#include is actually a preprocessor-directive, which means, they are resolved before compilation. #include实际上是一个预处理器指令,这意味着它们编译之前被解析。 The preprocessor processes every translation unit seperately and two translation units do not influence each other.预处理器分别处理每个翻译单元,两个翻译单元互不影响。 The results of this step don't contain any preprocessor statements (like #include , #ifdef , #define , etc).此步骤的结果不包含任何预处理器语句(如#include#ifdef#define等)。

So after preprocessing, both files, file1.cpp and file2.cpp , contain the contents of header.hpp .因此在预处理之后, file1.cppfile2.cpp两个文件都包含header.hpp的内容。 Then both are compiled to file1.o and file2.o .然后两者都编译为file1.ofile2.o No problems so far.到目前为止没有问题。 Here comes the importance of include guards.这就是包含守卫的重要性。 Compilation will fail if a translation unit contains duplicate declarations.如果翻译单元包含重复的声明,编译将失败。

Imagine you got a header1.hpp :想象一下你有一个header1.hpp

#include "header.hpp"

class ABC { ... };

And header2.hpp :header2.hpp

#include "header.hpp"

class XYZ { ... };

And some file, say, file3.cpp would rely on both:还有一些文件,比如file3.cpp将依赖于两者:

#include "header1.hpp"
#include "header2.hpp"

class Foo : pulbic ABC, public XYZ {};

Without include guards you end end with including header.hpp twice and get all the declarations twice in the translation unit, which doesn't compile.如果没有包含守卫,你会以包含header.hpp两次结束,并在翻译单元中两次获得所有声明,这不会编译。 (We are only looking at file3.cpp here). (我们在这里查看file3.cpp )。 With include guards header.hpp is only included once .使用包含保护header.hpp只包含一次

Now we finally reached the linking stage and come back to your original example.现在我们终于到达了链接阶段,回到你最初的例子。 You have 2 compilation units, that both contain all the decalrations from header.hpp .您有 2 个编译单元,它们都包含header.hpp所有声明。 The linker will not care about duplicate declarations.链接器不会关心重复的声明。 The linker will only fail if it finds multiple definitions of a symbol.链接器只有在找到一个符号的多个定义时才会失败。

The #include s are not "checked" or "ignored" at the linking stage, they simply don't exist any more. #include在链接阶段不会被“检查”或“忽略”,它们根本就不存在了。

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

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