08 - H files versus C files

Submitted by Webbot on September 24, 2008 - 9:39pm.

 

So we seem to be able to place code into both .h and .c files - what's the difference.

 

In the 'good old days' - the difference was that anything in the .h files was placed 'inline' whereas anything in your .c file was only compiled once. An 'inline' is where the code is substituted into your main code every time you use it. So lets assume you have a header file that defines:-

int increment(int v){

   return v=v+1;

}

Then in your main code you can do:

int x=0;

int y=0;

x = increment(x);

y = increment(y);

 

The compiler would then substitute the 'increment' code as if you had written:-

int x=0;

int y=0;

x = x+1;

y= y+1;

 

This 'inlining' is fine if the code is small - but what if its 100s of lines long? Then your program may grow by several hundred bytes every time you used it. So then you would place the code into a .c file and compile it into a library. The header file would then change to say:

extern int increment(int v);

to indicate that there is a method called 'increment' which accepts an integer and returns an integer result. This would mean that the code for the body of the function was only included one and any code that referenced it would call this code.

 

This meant that if you wanted to share your code with a 3rd party (but not let them change it) you could just give them the .h files (which contain some very simple code) and the pre-compiled libraries (with all the complicated stuff already compiled and cannot be changed).

 

Nowadays, and with avr-gcc compiler, it would appear that this is no longer the case. If you define a method in a .h file then it is normally only compiled once and any references to it end up calling it. So the difference between .h and .c is small. Even if you define a method in a .h file that is never called then it still gets compiled. Equally: if you compile a .c file into a library and the rest of the code only accesses one of the methods in that file then the entire compiled .c file will be added to your program.

 

So the differences between .h and .c are narrowing.

 

BUT - here is a big difference. If you have code in a .c file that is compiled and placed into a library then it is compiled using the makefile settings at that time. So if you compile the file using a makefile saying that its for a 1MHz ATMega8 with No optimisation then that is how it is stored into the library. If you then write another program for an 8MHz ATMega168 with optimisation for speed which then links in code from the library then the library code will still be 1MHz ATMega8 with No optimisation.So if you keep changing platforms then you will need to keep rebuilding the libraries.

 

However: a .h file is always interpreted at compile time. So anything that refers to variables such as F_CPU (the processor clock speed) should be placed into a .h file so that the code picks up the correct value every time.

 

If you look at the avr-lib then you will see that they don't really offer much in the way of a pre-compiled library. You are encouraged to re-compile their .h and .c files within your own project - this is to make sure that it picks up the latest settings from your makefile. I think that this is a common approach with microcontrollers where there are so many different makes/speeds etc that it is difficult to supply any pre-compiled library that works in every situation.

 

If you examine my 'makefile' then you will see that there is an option to specify where your avr-lib is installed. This makes the compiler search this folder for any files as well as your main code directory. So you don't have to cut and paste the file from avr-lib into your own project.