>i mean they have no source code but yet they still accomplish something, how?
They accomplish nothing more than declarations. To use a name in C it must first be declared, a header file performs this task. However, declarations must have a definition before being used. That's where implementation files come in.
A header file (*.h) is where the declarations reside, you use it to tell a program what names you intend to use and how. An implementation file (*.c) defines those declarations and is compile/linked to your program. For example, you have three files:
Code:
/* ctest.c */
#include "test.h"
int main(void)
{
f("Hello, world");
return 0;
}
Code:
/* test.h */
void f(char *msg);
Code:
/* test.c */
#include <stdio.h>
void f(char *msg)
{
puts(msg);
}
Now you can compile test.c separately like so (assuming a Borland compiler for no reason):
%>bcc32 -c test.c
This compiles test.c and produces an .obj file. To compile ctest.c using test.h, you simply compile ctest.c and link test.obj:
%>bcc32 ctest.c test.obj
This separates the compilation and linking stages, but the advantages aren't obvious until you work on larger projects where recompilation of the entire program is very slow. Another alternative is to compile and link all in one shot:
%>bcc32 test.c ctest.c
So to answer your question, when required, header files have source code attached to them through implementation files which are linked in after compilation. The header file itself is there to make sure that your program knows what names are available during compilation (programs are compiled before they are linked, so you need the declarations). If the definitions do not exist, you get linker errors.