Programming/C++/Headers and File Including
C Program Compilation Process
To understand anything else on this page, we first must go over how a C program compiles.
Step 1 - Pre-Processor & Compiler
First, a "pre-processor" runs on every file within the given C program. This pre-processor manipulates code in preparation for the compiler. For example, it:
- Removes all code comments, since those are meant for the programmers, and ignored by the system anyways during program runtime.
- Finds all defined macros in code, and changes them to the equivalent source code it's meant to represent.
- Various other optimizations prior to actually running the compiler.
Once the pre-processor is finished, the Compiler actually translates this code to a low-level Assembly code file (generally with the file extension .s
).
By the time these steps are complete, we should have an equivalent assembly file for every file in the project. This assembly file is optimized to be as efficient as possible. See Programming/Compilers for more information on what a compiler actually does.
Step 2 - Assembler
Once the project is converted to assembly files, an Assembler reads these in, and further minimizes/optimizes them into even lower-level object files (generally with the file extension .o
or .obj
).
The difference between an assembly file and an object file is that assembly is a series of codes. While a pain, they technically can be read and understood by humans.
Meanwhile, object files go a step lower, and are pure binary. They are designed purely to be as efficient as possible for a processor to read, and are not human-readable.
Step 3 - Linker
A Linker then takes all of these generated object files and determines how they fit together as far as the overall program being compiled.
For example, any internal project files that are still separate at this point are combined. Any system libraries that are referenced in the code are pulled into memory, and then combined with these files. The end result is a final, single executable file, that represents the final result of the program.
Compilation is done.
Project Organization
Organizing Function Declarations
The C language is quirky in how functions have to be defined. Effectively, a given value must be defined ABOVE where it will be used. Like physically above, in the code.
So for example, int main()
is the standard entry point for any given C/C++ project. If a given program were to be written all in a single file, then there are two options:
Option #1 (Naive solution) - Define all functions at the top, and main()
at the bottom as the very last function.
<system library "include" headers here> void my_func_1(...) { # Function logic here. ... } void my_func_2(...) { # Function logic here. ... } ... void my_func_n(...) { # Function logic here. ... } int main(...) { # Program entrypoint logic here. ... }
Option #2 - Create Function Declarations at the top of the file, and define the functions lower in an organized manner:
<system library "include" headers here> # Function declarations. <type> my_func_1(); <type> my_func_2(); <type> my_func_3(); int main(...) { # Program entrypoint logic here. ... } <type> my_func_1(...) { # Function logic here. ... } <type> my_func_2(...) { # Function logic here. ... } ... <type> my_func_n(...) { # Function logic here. ... }
Using Header Files
We can take the above Function Declarations logic a step further, by splitting code into separate files.