Header Files
Re:Header Files
A header file is just a simple text file where you put things that someone would need to know in order to use your code (constants, procedure headers, etc). For instance, given this:
MyCode.c
You could split it into
MyCode.h
MyCode.c
In the second case the header file gives all the information you need to know (with comments where appropriate) without the distraction of blocks of code. Another advantage is that you can distribute the header plus the code in object file form in which case people can still look in the header to find what they need but can't see the code if you don't want them to.
Edit:
That probably won't compile under standard C (due to the typedef I believe), I'm too used to C++, but the same things apply.
MyCode.c
Code: Select all
const int ONE_THING = 0;
const int ANOTHER_THING = 1;
typedef struct SomeInfo {
int type;
char *name;
} SomeInfo;
SomeInfo CreateStruct(int type, char *name)
{
SomeInfo newStruct;
newStruct.type = type;
newStruct.name = name;
return newStruct;
}
MyCode.h
Code: Select all
const int ONE_THING = 0;
const int ANOTHER_THING = 1;
typedef struct SomeInfo {
int type;
char *name;
} SomeInfo;
SomeInfo CreateStruct(int type, char *name);
Code: Select all
#include "MyCode.h"
SomeInfo CreateStruct(int type, char *name)
{
SomeInfo newStruct;
newStruct.type = type;
newStruct.name = name;
return newStruct;
}
Edit:
That probably won't compile under standard C (due to the typedef I believe), I'm too used to C++, but the same things apply.
Re:Header Files
But i don't know. How can i hide the source code of header file? Is compiling? If this, how can i compile header file? Is it different? ::) ;D
(I'm new at C. )
(I'm new at C. )
Re:Header Files
Basically, the useful code itself is in the .c file, the defines and suchlike are in the .h file. If you compile the pair you will get an object file produced which can be linked into any program, you would distribute the header file for people to include in their program to give them a way to interface with that.
Re:Header Files
Consider:
This will generate a compiler message about "implicit declaration of function puts()", because how should the compiler know what [tt]puts()[/tt] is, what parameters it takes, what its return code is?
(If you do not get that message, do get into the habit of running your compiler with warnings enabled. For gcc, that's the [tt]-Wall[/tt] option.)
Mind you, it will compile nevertheless, because compilers are forgiving beasts. The linker will then try to find [tt]puts()[/tt] somewhere - and will be successful, as it is a function of the standard library.
Now, consider:
The compiler warning is gone - you told the compiler that there is a [tt]puts()[/tt], what its parameters and return code are.
But do you really want to tell the compiler what [tt]puts()[/tt] is about in every file you use it in? No, surely not.
And you don't want to look up the correct declaration for [tt]puts()[/tt] each time, either.
That's why you write:
This tells the preprocessor to replace the line [tt]#include <stdio.h>[/tt] with the contents of the file stdio.h. This file, among others, contains the line
And you're done.
This means, you don't "compile" header files, you "include" them. A well-behaved header contains no code, only [tt]#define[/tt]s, [tt]typedef[/tt]s and declaractions.
The code for the function [tt]puts()[/tt] has been compiled long before, and there's object code for that function in the standard library. The linker will find it and link it to your executable.
Now, you can do the same for your code. Consider:
Save that to "foo.h". Then write:
Save that to "foo.c". Putting foo.h in quotation marks instead of angle brackets means, "search the file in the current directory, not the system include path". Including your own header is something that starts making sense later on, when there are structures and #defines in the header which you need in your function, too.
Compile with [tt]gcc -Wall -c foo.c[/tt]. Behold the "-c" option telling the compiler to stop after compiling the object file - it will not try to generate an executable, which would fail anyway because there is no [tt]int main()[/tt].
Delete foo.c. For demonstration purposes. Now, there is no longer any source for [tt]foo()[/tt] - only the header (foo.h) and an object file (foo.o).
Then write:
Trying to compile that with [tt]gcc -Wall main.c[/tt] will fail, because the linker complains it cannot find [tt]foo[/tt].
Compile with [tt]gcc -Wall main.c foo.o[/tt], and you will get a complete executable printing "Hello world!" when executed.
Now, when you start amounting functions, and put them in various .c files, the final compilation command becomes longer and longer because of all the .o files appended to it. Sooner or later, the command will fail because it exceeds the maximum length allowed by your shell. There is a solution though:
When you have, say, [tt]foo.o[/tt] and [tt]bar.o[/tt] and [tt]baz.o[/tt], you can create a linker archive with the following command:
[tt]ar r mylib.a foo.o bar.o baz.o[/tt]
You can name it something else than "mylib.a", of course. All three object files end up in the linker archive mylib.a - you could delete them if you want.
Then, if you wrote a main.c that uses functions from all three those object files, you include the relevant header files, and compile with [tt]gcc -Wall main.c mylib.a[/tt] to get your executable. The headers tell the compiler what functions are available, and the linker archive provides the object code for them.
I hope this helps shedding a bit of light on header files, and what to use them for. For details on "ar", like how to add or remove elements from it, please refer to its documentation.
Code: Select all
int main()
{
puts( "Hello world!" );
return 0;
}
(If you do not get that message, do get into the habit of running your compiler with warnings enabled. For gcc, that's the [tt]-Wall[/tt] option.)
Mind you, it will compile nevertheless, because compilers are forgiving beasts. The linker will then try to find [tt]puts()[/tt] somewhere - and will be successful, as it is a function of the standard library.
Now, consider:
Code: Select all
int puts( const char * );
int main()
{
puts( "Hello world!" );
return 0;
}
But do you really want to tell the compiler what [tt]puts()[/tt] is about in every file you use it in? No, surely not.
And you don't want to look up the correct declaration for [tt]puts()[/tt] each time, either.
That's why you write:
Code: Select all
#include <stdio.h>
int main()
{
puts( "Hello world!" );
return 0;
}
Code: Select all
int puts( const char * );
This means, you don't "compile" header files, you "include" them. A well-behaved header contains no code, only [tt]#define[/tt]s, [tt]typedef[/tt]s and declaractions.
The code for the function [tt]puts()[/tt] has been compiled long before, and there's object code for that function in the standard library. The linker will find it and link it to your executable.
Now, you can do the same for your code. Consider:
Code: Select all
void foo();
Code: Select all
#include <stdio.h>
#include "foo.h"
void foo()
{
puts( "Hello world!" );
}
Compile with [tt]gcc -Wall -c foo.c[/tt]. Behold the "-c" option telling the compiler to stop after compiling the object file - it will not try to generate an executable, which would fail anyway because there is no [tt]int main()[/tt].
Delete foo.c. For demonstration purposes. Now, there is no longer any source for [tt]foo()[/tt] - only the header (foo.h) and an object file (foo.o).
Then write:
Code: Select all
#include "foo.h"
int main()
{
foo();
return 0;
}
Compile with [tt]gcc -Wall main.c foo.o[/tt], and you will get a complete executable printing "Hello world!" when executed.
Now, when you start amounting functions, and put them in various .c files, the final compilation command becomes longer and longer because of all the .o files appended to it. Sooner or later, the command will fail because it exceeds the maximum length allowed by your shell. There is a solution though:
When you have, say, [tt]foo.o[/tt] and [tt]bar.o[/tt] and [tt]baz.o[/tt], you can create a linker archive with the following command:
[tt]ar r mylib.a foo.o bar.o baz.o[/tt]
You can name it something else than "mylib.a", of course. All three object files end up in the linker archive mylib.a - you could delete them if you want.
Then, if you wrote a main.c that uses functions from all three those object files, you include the relevant header files, and compile with [tt]gcc -Wall main.c mylib.a[/tt] to get your executable. The headers tell the compiler what functions are available, and the linker archive provides the object code for them.
I hope this helps shedding a bit of light on header files, and what to use them for. For details on "ar", like how to add or remove elements from it, please refer to its documentation.
Every good solution is obvious once you've found it.
Re:Header Files
Here is some additional material on the actual maechanics of the #include statement (from this tutorial):
And yes, I know I never fixed a lot of the errors in that tutorial; I need to go back through it again but I never seem to find the time. Any help in spotting mistakes would be appreciated.The directive
[tt]#include "path/filename"[/tt]
or
[tt]#include <path/filename>[/tt]
...will cause the text of [tt]filename[/tt] to be inserted into the source stream at the point where the directive occurs. For example, given the file foo.h,which is then used in file foo.cCode: Select all
/* foo.h */ extern int bar; float foo();
Code: Select all
/* foo.c */ float baz = 3; #include "foo.h" int bar = 10; float foo() { return bar * baz; /* multiply the current values of bar and baz */ }
the preprocessor would produce:Code: Select all
float baz = 3; extern int bar; float foo(); int bar = 10; float foo() { return bar * baz; }
By long-standing convention, this is used almost exclusively to include header files, which are source files containing only constant definitions, type and class definitions,external variable references, and function prototypes which are to be shared between two or more source files. Generally speaking, actual variable declarations and function definitions are not put into header files, as this can lead to redeclaration errors when linking the resulting object files.