Hallo allemaal,
For most of my projects I used Turbo Pascal so far. I studied C but
more to see how programs were made and then to write them in TP. I
decided to start in writing in C as well and best practice is just to
do it. But I ran into a problem: I don't know exactly how to program
using multiple files.
Those of you familiar with Pascal will know 'units' and 'uses'. AFAIK
you need H-files in C to do the same trick. But that didn't work out
under Borland C 3.1. Until I added the two files (in this case) to a
project AND used an H-file, I had success. But when I added a variable
to the H-file, the compiler complainted about declaring this variable
in both CPP files. I looked through various books I have, including
user na programmers manual of BC 3.1 but I couldn't find a chapter
that explained things (or I missed it).
Can anybody point me to an URL, PDF, document or whatever that
explains the ins and outs of using multiple files, preferably under
BC?
Thank you very much in advance!
Groetjes, Ruud Baltissenwww.Baltissen.org
Nah, off the top of my head I can't think of a link or
a book on the topic, I think you have to learn this stuff
in the gutter...
In any event, I don't think there is any difference
between linking in Borland compilers or any other
compiler in terms of what goes in .h and .c files, so
that's not your problem. Your problem seems to be
a lack of knowledge of some basic facts about "C",
specifically how external declarations and linkages
are handled...
I can't tell from your post exactly what the problem
was, but in general it looks like you are just doing
stuff at random to see what happened. I mean, what
was the point of declaring a variable in the .h file
in the first place? If you didn't have a reason, THAT'S
your GENERAL problem...
The reason you want a .h file is generally to
declare prototypes for functions that are in other .c
files, so they can be correctly compiled and linked
with your current .c file. You also can use a .h
file to declare data types and variables that
will be used in several different .c files, and
even use the "extern" keyword to link a variable
that is declared and defined in another .c file
with your current .c file.
Remember that the "h" suffix stands for "header",
because all of the stuff in the .h file should go
at or near the top (or "head") of the .c file, to
satisfy "C"'s rules for declaring variables and
functions. When you use the "#include" directive
the "preprocessor" merely replaces the directive with
the .h file contents at the point of the directive in
your .c file before it is compiled (all "#" directives
are just search and replace commands that re-write
the .c file before it is compiled to a linkable
..o object file). So the .h file is largely just
a shortcut to having to laboriously type in common
and external declarations at the top of many .c
files, rather than something that has "special"
properties.
You can see how all of this works as a practical
matter in the "standard libraries" of "C". For
one example, the "standard libraries" have functions
for getting the current time and displaying it.
In writing YOUR "C" programs, you might find that
you want to do that dozens (or maybe hundreds) of times,
so it's nice that it's already been done for you
and all you have to do is call the pre-written
and compiled functions rather than write them
yourself. If you can think of something that
you would want to do dozens (or hundreds) of
times that is NOT part of the "standard libraries"
(and of course there are like a billion useful
functions not included in those libraries, like
just about everything you'd want to do), THAT'S
when you want to write the functions in a .c
file and create an .h file to make it easy to
link your future .c files with the output .o
file of your personal "library" .c file.
Remember (if you've used the "C" time
functions) how it works; at or near the
top of your .c file, you "include" the
"time.h" file:
#include <time.h>
That'll write all the declarations in the
time.h file in your .c file. Included will
be the type declarations for "tm" and
"time_t" and function prototypes for
"time()" and "localtime()". So now you
can get the current time and display it in
your .c file by first declaring your own variables
using the time.h type declarations:
static time_t my_c_time;
static struct tm *my_c_time_struct;
And then you can get the current time
as the number of seconds after a certain
date by calling the function "time()":
/* gets date and time from system as number of seconds from 1/1/1970
*/
time(&my_c_time);
And get the various time elements (month, day,
year, etc.) from "my_c_time" using "localtime()":
/* converts date/time to a structure */
my_c_time_struct=localtime(&my_c_time);
And then you can print the day of the
month to the standard output using another
"standard library" function "printf()" that
you can use if you "#include <stdio.h>":
printf("%d",my_c_time_struct->tm_mday);
So again, you probably only want to use a
..h file if you are creating your own "libraries"
of functions and data types that you will use in many
future "C" programs...
Oh, one more thing, it's actually pretty
important...you can run into all kinds of weird
problems when you "#include" one .h file in
another .h file and wind up with multiple
declaration messages when you try to compile
a .c file. There is a pretty common method
to avoid MOST of these problems called an
"include guard" that makes the .h file
"idempotent" (only actually included once when
compiling and linking multiple files). The
trick is to make the whole .h file conditional
on whether the compiler has encountered it
before using "#if" directives to set a unique
flag for the file.
As an example, for my CSV file parsing
"library", the csvfls.h file is set up like
this:
#ifndef csvflsH
#define csvflsH
<actual .h file goes here>
#endif
The flag "csvflsH" is derived from the
name of the csvfls.h file and is hopefully
unique, because "#ifndef" causes the preprocessor
to check that it has not been set (or "defined")
before; if it has, everything to the "#endif"
at the bottom of the file is ignored. If it
hasn't, then the "#define" directive sets ("defines"
it and the entire .h file is included, but
will not be included again because now the
"csvflsH" flag has been set.