Hmm, well I'm not great at C/C++ but I'll give it a go explaining. C code:
Code: Select all
/* my_func.c */
void my_func(void){
/*Do Something*/
}
---------------------------
/* my_func.h */
%ifndef FUNCTION1
%define FUNCTION1
extern void my_func(void);
%endif
---------------------------
/* main.c */
#include "my_func.h"
int main(void){
my_func();
return 0;
}
Ok, nothing amazing codewise I know.
I'll go through in steps.
First you compile the two .c files into .o (Object format) files. This gives you my_func.o and main.o.
Now the final step in creating an executable is to link together the object files using the linker.
The important thing here is that because my_func.h has been included into main.c, and most especially because my_func.h declares that there is an function called my_func() that is external (Ie not declared in) main.c, the file main.o will contain instructions telling the linker that there is an external function called my_func() that main.o contains references to.
The linker is then smart enough to figure out that my_func.o contains the function my_func() and whilst creating the executable makes sure that any references to it in main.c use the funtion in my_func.
Ok, not very interesting (And a seriously simplified view of linking) so far.
The useful part comes when you realise that you don't have to recompile my_func.c into my_func.o anymore unless you change the my_func.c source file.
So long as my_func.c remains unchanged, and you still have my_func.o, it doesn't matter how much you alter main.c, becuase as long as it still includes my_func.h the linker will still have enough information to create the executable. Ie you only have to recompile the file you change and then link everything together again.
Now to take this to a larger example. Let's say you're working on a project with a few hundred source files, which comprise a few megabytes of code. Recompiling everything for every minor change would become tedious in the extreme. Now what something like make does is check to see which source files have changed since the last time an executable was created. It then compiles these changed source files into object format and links all the object files together (The old ones from files that are unchanged + the new ones from files that have changed) into the new executable. This is
far more efficient.
Hope that helps, if there's any errors hopefully one of the C/C++ gurus will point 'em out.
**
Note: The define is there to stop the function being declared twice should the header be included into multiple source files.
**
Almost forgot to mention the other important way these header files are used...libraries.
Let's say, for instance, you include math.h into a standard C file because you want to use the sin() function. Now if you take a look at math.h all you'll find are a lot of definitions of constants and a lot of function prototypes. At link time the linker uses those function prototypes to change references to sin() within your C file to point at the entry to the sin() function within the standard C library. Same principle as before, only the standard C library has taken the place of the my_func.o object file.