Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > How do header files work?

Reply
Thread Tools

How do header files work?

 
 
Dan Moos
Guest
Posts: n/a
 
      05-19-2004


Here is what I think you understand so far. You have some class, called cat

class cat{}

that is what the .h file would have. In a seperate .cpp file, you would have
all of cat's methods defined. This .cpp gets compiled into an .obj withe the
rest of your code.


Now, you just include the cat.h file in any source file where a cat class
might be needed.

This much I think you understand. Now for the part I think you don't get.

By including cat.h. your telling your source file abouut the cat class. That
way, evrytime the compiler sees a cat class in your source file, it knows
that it is a valid class. You are "exposing" cat classes to tha source file.
At this point, the compiler doesn't know or care whether the definition of
cat's methods actually exists. That is the linker's job. The inclusion of
the header only makes cat classes availiable to that particular source file.
If the linker can't find a .obj file that defines a cat, then you get an
unresolved external link error of some sort. In this case, your source file
compiles fine because the .h file says a cat class is a valid type, but if
there isn't a coorasponding .obj file, the link will fail. For what it's
worth, the cat.cpp file must include cat.h also, for the same reasons.

Here is a good experiment. Basically, try creating the scenario I just
described, and when it all works, I think you'll underestand. do this:

write an .h file that has the class definition for a cat. NOT THE METHODS!
just the basic class.

write a .cpp file that defines cat's methods. Make sure and #include cat.h
in this .cpp file

write a mainprogram.cpp file that uses cats somehow. Make sure and #include
cat.h in this file also

compile and link the whole shebang

let us know how it goes!




 
Reply With Quote
 
 
 
 
Alan Johnson
Guest
Posts: n/a
 
      05-20-2004
matthurne wrote:

> My next question would be, how?


The answer is that is depends on the specific compiler/linker.

Let's work through an example from start to finish, and maybe it will
help clarify things.

First, let's make a source file:

stuff.cpp
-----
int f(int x)
{
return x ;
}

int g(int x)
{
return x*x ;
}


Now, we compile this source file, using whatever method our compiler
likes. What get's generated? On most compilers, a file called
"stuff.o" or "stuff.obj" would be generated. Exactly what is in this
file depends on the compiler, but it contains, at a minimum, the
compiled code for the functions f and g, and probably some sort of
symbol table that says "this block of data represents the compiled code
for f", and "this block of data represents the compiled code for g".

Now, for the convenience of everybody who might use f and g, let's
create a header file:

stuff.h
------
int f(int x) ;
int g(int x) ;

It doesn't make any sense to "compile" a header file. There is no
executable code there. The first line simply says, "somewhere (we
aren't specifying where, but somewhere), there is a function in
existance called f, and this function takes one integer as a parameter,
and returns an integer." The second line says a similar thing about g.

Time for another source file:

main.cpp
--------
#include "stuff.h"

int main()
{
int y ;
y = f(3) + g(2) ;
return 0 ;
}

Now, we compile main.cpp. The very first thing the compiler does is run
main.cpp through what is called the "preprocessor". The preprocessor
sees the include statement, and replaces it with the contents of stuff.h
, so by the time it gets to the more interesting phases of compiling, it
looks like this:

preprocessed main.cpp
---------------------
int f(int x) ;
int g(int x) ;

int main()
{
int y ;
y = f(3) + g(2) ;
return 0 ;
}


As before, the compiler is going to emit an object file called something
like "main.o" or "main.obj". This object file will contain the compiled
version of the function main, and probably a symbol table that has
'main' in it somewhere. An interesting question is how this line gets
compiled:

y = f(3) + g(2) ;

After all, the compiler, at this point, doesn't know very much about f
and g. It certainly doesn't know anything about the actual compiled
versions of f and g, as that got created during a completely different
run of the compiler, and it doesn't have any idea where to begin looking
for it now. It does know, however, because of the first two lines that
declare f and g, that f and g exist somewhere, that they each take an
integer as a parameter, and each return an int. That is enough
information to at least make sure that the functions are being used
correctly. Instead of actually putting all of the code necessary to
call f and g into the object file (which it can't do, because, if you
recall, it doesn't know where f and g are), it is content to put some
sort of marker that says "I need to call some function called f right
here", and similarly for g.

So, now we've compiled both our source files, and have two object files,
which for sake of argument we'll say are "stuff.o" and "main.o". The
next step is to combine these together into a program that someone could
actually run. That is where the linker comes in. When we use the
linker, we give it ALL the object files at the same time, rather than
one at a time. So, here is a (highly simplified) dramatization of what
happens in the linker:

1. I know that programs need to start at a function called "main", so I
need to find that.
2. Here it is, in "main.o". So, I'll copy this compiled code into the
executable I'm creating.
3. But wait! This function called "main" needs to call some function
called "f", so I need to find that.
4. Here it is, in "stuff.o". So, I'll copy this compiled code for "f"
into the executable, and replace the marker in "main" with the actual
location of "f".
5. "main" needs another function called "g", so I need to find that.
6. Here it is, in "stuff.o". So, I'll copy this compiled code for "g"
into the executable, and replace the marker in "main" with the actual
location of "g".
7. It doesn't look like anything else is needed, so I'll write out this
executable in the proper format for this operating system.


At this point, we have a real, working executable (which, admittedly,
doesn't do very much). There are a couple of other things that are
worth mentioning, that may often confuse people.

First, many object files are often stuffed together into one large file
that we call a library. It is quite likely that whatever compiler you
are using has the code for its C++ library functions stored like this.

Second, many compilers will, by default, automatically call the linker
after they are finished compiling, and in some cases may not bother to
actually write out the object files to disk. For example, consider
compiling this with g++ in the following manner:

$ g++ main.cpp stuff.cpp

Now, looking in the directory, we see:

$ ls
a.out main.cpp stuff.cpp stuff.h

If you are not familiar with g++, a.out is the name given to executables
if you do not explicitly tell it a name. But, as you can see, no object
files were created. At least, they weren't saved on the disk. You can
be pretty sure that g++ went through the process of creating them in
memory (or temporary files), and then invoked the linker to combine
them. Consider an alternative approach, in which we explicitly tell g++
to only compile (but not invoke the linker) :

$ g++ main.cpp

$ g++ stuff.cpp

Now, let g++ invoke the linker on the object files:

$ g++ main.o stuff.cpp

$ ls
a.out main.cpp main.o stuff.cpp stuff.h stuff.o


The executable got created just the same. So what is the advantage of
doing it this way? With large projects, compilation can take a long
time. So if we are careful (and there are tools to help) we can get
away with only recompiling the source files that we change, and then
just relink everything together. Look up 'Makefile' or 'make' for more
information.

I hope this helps,
Alan



 
Reply With Quote
 
 
 
 
David Harmon
Guest
Posts: n/a
 
      05-20-2004
On 19 May 2004 07:50:44 -0700 in comp.lang.c++, http://www.velocityreviews.com/forums/(E-Mail Removed)
(matthurne) wrote,
>Basically, I don't understand how a header file being
>included makes a connection with the source file that has the
>definitions for whatever is in the header file.


As you guessed, this is implementation specific.

A typical implementation might be, the definitions are all precompiled
and the resulting object code combined into "library" files that are
indexed in such a way as to make them easy to search. Then when you
call some library function, there is a step that searches the library
file(s) for the matching definitions and links them with your code into
an executable program.

 
Reply With Quote
 
JKop
Guest
Posts: n/a
 
      05-20-2004
matthurne posted:


> I think the answer to my ultimate question came from Michael...the
> linker is what makes the connection between the function declaration
> and definition, correct? My next question would be, how?


Take the two following Object files:

choclate.obj
icecream.obj


"chocolate.obj" will have a sort of Contents at the start of it. It will say
what functions it has and what global variables it has. Maybe it'll look
like this:

void MakeChocolateChips(void) //A function
unsigned int DiameterOfChocolateChip //A global variable
void HeatChocolate(unsigned int) //A function


"icecream.obj"'s contents:

int PickFlavour(void) //A function
double GetVolume(void) //A function
double DensityOfIcecream //A global variable



So now the linker takes over. It throws all the object files together,
resulting in:


void MakeChocolateChips(void) //A function
unsigned int DiameterOfChocolateChip //A global variable
void HeatChocolate(unsigned int) //A function
int PickFlavour(void) //A function
double GetVolume(void) //A function
double DensityOfIcecream //A global variable


Now, Let's say "int PickFlavour(void)" calls "void MakeChocolateChips
(void)", it'll find it because the linker has introduced all the object
files to each other and made one entire entity out of them.


Moving on...


Let's say you have a function in "chocolate.obj" as so:

void Hello(void);

And you also have a function in "icecream.obj" as so:

void Hello(void);


When the linker throws everything together, what do you think is going to
happen?... Exactly, Multiple Definition. Link Error.

Let's say that the function "void MakeChocolateChips(void)" in
"chocolate.obj" calls the function "void Hello(void)" in "chocolate.obj".
But if you try link, you'll get a Multiple Definition error. What you want
to do is remove "void Hello(void)" from the Contents of the "chocolate.obj"
file, thus giving it Internal Linkage, so the Linker won't throw it in with
everything else. To achieve this, you do the following in "chocolate.cpp":

static void Hello(void);


Now "void Hello(void)" can only be seen from within "chocolate.obj". It has
internal linkage. Now the prog will link without error. You can do the same
with the global variables:

static int monkey;


> Something tells me that gets into issues I probably won't understand.
> If anyone can throw it into "just finished his sophomore year of
> undergraduate school for computer science" language, go ahead and try!


I left school went I was 16. Learned C++ from a book or two. I'm now 17.



Hope that helps


-JKop
 
Reply With Quote
 
matthurne
Guest
Posts: n/a
 
      05-20-2004
Ok, well I think between all of you my question was answered! At
least for now... My main curiosity had to do with the linker and
how it works, though when I first started this thread I didn't know
it. Alan's post was especially helpful...btw, I'm using Slackware and
g++ exclusively since that's what I run on my desktop...I did figure
out on my own that if I just compiled all the files together, it "just
worked"...now I better understand that g++ did all the steps for me.
g++ -c will compile only to object files. g++ -v was a nice way for
me to see all the commands g++ was running, including the linking.

I'm satisfied, but if you aren't, feel free to post some more. Thanks
everyone.

P.S. JKop, I hope your programming abilities with leaving school at
16 doesn't mean my $27,000 a year is a waste! Ahhh!
 
Reply With Quote
 
JKop
Guest
Posts: n/a
 
      05-21-2004
matthurne posted:

> P.S. JKop, I hope your programming abilities with leaving school at
> 16 doesn't mean my $27,000 a year is a waste! Ahhh!



Stereotypes are there to be broken.

Education, as with beauty, is in the eye of the beholder.


-JKop

 
Reply With Quote
 
Alan Johnson
Guest
Posts: n/a
 
      05-21-2004
Alan Johnson wrote:

> $ g++ main.o stuff.cpp


One correction ... this should have been, obviously:

$ g++ main.o stuff.o


Sorry for any confusion.

Alan
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
Header files with "header.h" or <header.h> ?? mlt C++ 2 01-31-2009 02:54 PM
UNIX header files to Windows header files anand.ba@gmail.com C Programming 3 05-01-2006 03:57 PM
Header files included in header files John Smith C Programming 18 07-24-2004 04:55 AM
What is better /standard for creating files. a cpp file with header or cpp and seperate file for header DrUg13 C++ 1 02-10-2004 09:20 AM



Advertisments