0

A header file usually has some safe guard using the #ifndef directives(or similar) e.g:

//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 file2.cpp -o file2.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?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
mathmaniage
  • 299
  • 1
  • 14
  • 2
    `#include` has nothing to do with linking. Or compiling. It's done by the preprocessor. – L. F. Mar 06 '20 at 08:23
  • This works, unless you define variables of functions in your header files, which is wrong anyway because header file should only contain declarations. In the latter case the linker will show errors because you'll have duplicate function and variable names. – Jabberwocky Mar 06 '20 at 08:26
  • @L.F. , um... the preprocessor replaces all the code into both the files and during the linking stage what happens? – mathmaniage Mar 06 '20 at 08:30
  • @Jabberwocky , why would the former case work? Won't the declaration(not the definition) be twice? – mathmaniage Mar 06 '20 at 08:31
  • 2
    Nothing special happens during the linking stage. The result is the same if you manually copy the content of the header into the source files. – L. F. Mar 06 '20 at 08:38
  • @L.F. so while linking if it sees the #define twice it's gonna ignore that? – mathmaniage Mar 06 '20 at 08:45
  • @mathmaniage the linker doesn't see the `#defines`, they are processed even before the actual compiling process. – Jabberwocky Mar 06 '20 at 08:46
  • @mathmaniage [this](https://stackoverflow.com/questions/14604975/how-does-the-preprocessor-work-in-c) and [this](https://stackoverflow.com/questions/19464265/how-exactly-does-linking-work) help. – Jabberwocky Mar 06 '20 at 08:49
  • 1
    @mathmaniage again, the directives are processed ONLY during the preprocessor stage, which happens BEFORE the compiler stage, which happens BEFORE the linker stage. The linker has no concept of the directives, it only sees the code that the compiler produces, which in turn only sees the code that the preprocessor produces after performing macro substitutions. Given your example, the compiler will produce multiple object files containing the same symbols, which the linker will then discard the duplicates, or will error if they are not compatible with each other. – Remy Lebeau Mar 06 '20 at 08:59
  • @Jabberwocky , the second link you mention says this:" the stub references with actual "call this function" machine code instructions" , does it replace the entire function code there or calls to the function merging the file into the executable? – mathmaniage Mar 06 '20 at 09:25
  • 1
    @mathmaniage usually the latter, but nowadays compilers and linkers do a lot of smart things. You don't really need to care, at least at your level. – Jabberwocky Mar 06 '20 at 09:31
  • @Jabberwocky , how to increase my level? Is it experience or is there any resource you'd recommend? – mathmaniage Mar 06 '20 at 09:32
  • 1
    @mathmaniage "at your level" = "at beginner's level". – Jabberwocky Mar 06 '20 at 09:33

4 Answers4

1

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
1

The formal term here is "Translation Unit". That's what you call a single .cpp file with all the headers included by it. 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.

MSalters
  • 173,980
  • 10
  • 155
  • 350
0

Both are exactly the same. The Guard doesn't go to the next file. Every file is compiled with new #define - state.

0

#include is actually a preprocessor-directive, which means, they are resolved before compilation. 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).

So after preprocessing, both files, file1.cpp and file2.cpp, contain the contents of header.hpp. Then both are compiled to file1.o and file2.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:

#include "header.hpp"

class ABC { ... };

And header2.hpp:

#include "header.hpp"

class XYZ { ... };

And some file, say, file3.cpp would rely on both:

#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. (We are only looking at file3.cpp here). With include guards header.hpp is only included once.

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. The linker will not care about duplicate declarations. The linker will only fail if it finds multiple definitions of a symbol.

The #includes are not "checked" or "ignored" at the linking stage, they simply don't exist any more.

Lukas-T
  • 11,133
  • 3
  • 20
  • 30