1

Why does the source include a header and not also the other way around? I googled it but only found questions regarding the use of header files, how to include them but nowhere to say why it is like it is. If the header is merely the declaration, how does the compiler know the definition only from it?
For example: take foo.cpp, bar.h, bar.cpp. This is what everybody does:
in foo.cpp:
#include "bar.h"
but the bar.cpp is not included neither in the bar.h or foo.cpp. That's why I deem logical that bar.cpp be included in bar.h and so, indirectly in foo.cpp.

  • tl;dr legacy from C where it is legacy from dump compilers that could do symbolic import (as seen in every other language) – ratchet freak Feb 18 '15 at 10:40
  • "how does the compiler know the definition only from it [the header file]" - the compiler does not, why should it? – Doc Brown Feb 18 '15 at 12:30
5

Compilation of C and C++ code is done in two distinct steps.

In the first step, the source code in a single .c or .cpp file is compiled to object code. While compiling the file foo.cpp, the compiler needs to know that bar contains a method doSomething and what parameters that method expects and what return type it returns, but the compiler doesn't need to know exactly what the function does internally.
The compiler checks that the call in the code from foo.cpp matches how the function is declared (which is obtained by the #include "bar.h"), and then makes an annotation in the object code that at position X the function bar::doSomething is being called.

In the second step, all the source files that make up the application are linked together to create the final executable. At this point, the linker tries to replace the annotations that the compiler made in the object code with the actual address of the corresponding function. The linker is explicitly told which object files it should look at.
It is only at this point that the definitions of all functions need to be available.

Which files are needed to create an application is typically defined in a project file or a makefile.

  • 1
    Thank you for explanation but the question is how is bar.cpp made accessible? It's not #include-d into any of the headers or source files. How is the bar definition (not declaration) found? – mireazma Feb 19 '15 at 8:13
  • 1
    @mireazma: While compiling foo.cpp, the compiler doesn't need to access bar.cpp at all, so there is no need to make bar.cpp available. At the linking stage, the linker is told to combine foo.o and bar.o into an executable. There both object files are explicitly mentioned to the linker. It is also the linker that needs to have the definitions available. – Bart van Ingen Schenau Feb 19 '15 at 14:23
  • Added bonus: the *.o files can thus be compiled in parallel! (with a link step at the end) – J Trana Feb 20 '15 at 5:34
  • 1
    How does the compiler know to compile bar.cpp? Just because it's somewhere in the project and by default all cpps found are compiled or because the compiler searches for a homonym cppfor the corresponding h file #included in the dependency tree? – mireazma Feb 20 '15 at 8:19
  • @mireazma: The compiler knows to compiler bar.cpp because the IDE/make-tool tells it so, based on the fact that bar.cpp is listed as a source file in the project/makefile. – Bart van Ingen Schenau Feb 20 '15 at 10:21
4

Your question indicates that you don't understand the compilation process (most of this will apply to c as well as c++.)

The fundamental unit of compilation is a source file; for C++ the convention is to use the .cpp file extension. The extension could be anything, but most compilers use the extension to determine how to process the file, ex. .cpp means c++, .o means object, .c means straight c, etc. Source files are complied into object (nominally .obj or .o) files. Object files are linked together to create executable files.

The compiler doesn't know anything about header files. There is a pre-processor that replaces the #include directives with the content of the header file, and processes other pre-processor directives, the resulting output is what the compiler sees as input; this is the reason why headers are included in source files and not vice versa.

Header files aren't strictly necessary to compile source to object; they are a tool to manage complexity, organize and modularize your source files. As the other answers have explained, when foo.cpp needs to reference something in bar.cpp, say baz(), foo.cpp needs to have some descriptive information about baz() so it can generate a reference that the linker can resolve.

One could simply put this information in foo.cpp, but this would duplicate the information in bar.cpp. The solution to this duplication is to put all the descriptive information in another file, which we call a header file (nominally .h or .hpp.) With bar.h the information that needs to be included in foo.cpp and bar.cpp is only in one file, which is inserted into the file when the pre-processor finds the #include directive. This becomes invaluable as the complexity of the project increases.

Much of the compilation process is hidden behind an IDE or a makefile. Compiling a small project by hand will be very instructive in learning how the compilation process actually works. The first time I had to write a .makefile from scratch in school all mystery about the compilation process vanished; I had to learn all the details to accomplish the task.

Compiling and linking your example would be 3 operations, in two stages:

  • Compile the source files:
    • Compile foo.cpp into foo.o (ex. gcc -c -o foo.o foo.cpp)
    • Compile bar.cpp into bar.o (ex. gcc -c -o bar.o bar.cpp)
  • Link the object files:
    • link foo.o and bar.o into program (ex. gcc -o program foo.o bar.o)

During the compilation stage each file is processed individually. The resulting object files contain machine code and external references (things not in the source file, but located some other source file.)

The final step is to link the objects, this is when the references are resolved, if you forget to include the object file in the link command, it will fail with unresolved external references; this is the step where all the information is needed. Modern compilers can handle all those steps with a single command, but that hides the process.

  • Thank you but I still need to dot the I: Does the MSVS compiler without my explicit mention, compile all cpp files it finds in the project, even if not #included? Or just the ones corresponding to a same named h file? I'd personally preferred "strong definition" as in "strong type": compile what instructed, no more no less. – mireazma Feb 20 '15 at 8:12
  • The default behaviour of MSVS, and other IDEs, it to compile all the source files in that project. If you tell the IDE that your project depends on another, it will go off and compile that other project first (and so on, recursively). – Simon B Feb 20 '15 at 11:03
  • @mireazma putting a file into an IDE project IS "explicitly mentioning" it! i.e. and IDE project is equivalent to a .makefile. – esoterik Feb 23 '15 at 17:24
  • @esoterik: Unfortunately true. To make things even simpler and to go with the design, header files should be also auto-included -- they're in the project, right? This would at least spare us from managing which headers to include into which headers and source files and would cut out undefined errors. – mireazma Feb 23 '15 at 18:24
  • @mireazma newer languages like C# and Java, extract the 'header' information automatically, but they still require some sort of import directive to resolve references. The IDE can't read your mind, it won't know what headers you want to include. – esoterik Feb 23 '15 at 18:45
1

If bar.cpp included bar.h and vice versa, then there would be no point in having those two as separate files, since they would be effectively identical.

But there is a point: you don't need the definition for most tasks. Compiling a module that uses the services of bar only needs to know that bar contains a method doThings() which takes an int and returns an int. It does not need to know how bar achieves this (indeed, that is the entire point of modules). Therefore, when compiling another module, the compiler only bothers to read the header file, but when compiling bar itself it reads both files. In a large system composed of many modules, this saves a huge amount of effort because every line of definition code is compiled only once and not many times.

  • Thanks. So should I take it the compiler automatically reads cpp files based on their corresponding h names, and only if these h files are included somewhere in the execution "tree"? This is what I understand. – mireazma Feb 18 '15 at 10:52
  • Typically a compiler reads a .cpp file only if you explicitly tell it to, e.g. via gcc -o bar.o bar.cpp. It's the .h files that are read implicitly, because they're named in #include directives. – Kilian Foth Feb 18 '15 at 10:55
  • But this is precisely the question: how does the compiler/linker know of the unincluded cpp's, the ones corresponding to headers? How do they know where to look for the definitions of declared variables/functions in the headers? – mireazma Feb 19 '15 at 8:08
  • 2
    @mireazma: It doesn't. You have to tell the compiler to compile the sources you want compiled and those sources have to include the headers for things they need. Similarly, the linker has to be told to link the objects and libraries the program needs. – Blrfl Feb 19 '15 at 15:19
1

If you're a compiler, then Life is easy so long as you know what everything "looks like". For example, 'X' is a 64-bit integer, 'Y' is a pointer to something of that Type, 'Z' is an array of this Type and size, and so on. Take this to the extreme and you get an early Pascal compiler, where the main method has to be the very last thing in the source file! Everything else has to be defined first. Writing code in this way is painful, because the order is natural to the compiler but not to the likes of you and me.

Enter the Header (.h) file.

It describes all the methods that that appear in your .cpp file so the compiler can "make a note" of what they look like (known as "forward declarations") and then just recognise them when they appear, again, further down in the code. Otherwise, it just has to assume some "default" definition for any method and then complain like mad when it finds a different implmentation signature (some Solaris compilers assume "int methodName( int )" as a default, IIRC.

But, even with all this, you still don't need a Header file.

You can do all that within the .cpp file itself.

Now add "reusable code" into the mix. Other .cpp files want to use the methods in your .cpp file but the compiler still needs to know what those methods "look like".

By splitting the method declarations out into a Header file, you're effectively "publishing" the API provided by your .cpp file. (ADA has "package" and "package body", most of the Microsoft world just smooshes all the declaration and implementation details into a single file, the dll).

So the Header file gives you a single declaration of your methods, usable by both you and any number of others who might need to use those methods. Note, however, that the people using your Header file don't need your .cpp file at all; [object] code compiled in this way always has "holes" in it (unresolved function pointers); it's the linker's job to join all the dots together.

  • Yes, I know the use and usefulness of headers. Yet thank you for the informative answer. – mireazma Feb 20 '15 at 12:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.