Using multiple files in (Borland) C

R

Ruud

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 Baltissen
www.Baltissen.org
 
K

Keith Thompson

Ruud said:
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).

You shouldn't *define* variables in header files. You can *declare*
variables in .h files and *define them in .c files. That way you'll get
only one definition of the variable across your entire program.

A contrived example:

==> foo.h <==
#ifndef FOO_H
#define FOO_H

extern int foo_var;

void foo_func(void);

#endif

==> foo.c <==
#include "foo.h"
#include <stdio.h>

int foo_var = 10;

void foo_func(void) {
printf("In foo_func, foo_var = %d\n", foo_var);
}

==> bar.h <==
#ifndef BAR_H
#define BAR_H

extern int bar_var;

void bar_func(void);

#endif

==> bar.c <==
#include "bar.h"
#include <stdio.h>

int bar_var = 10;

void bar_func(void) {
printf("In bar_func, bar_var = %d\n", bar_var);
}

==> main.c <==
#include "foo.h"
#include "bar.h"

int main(void) {
foo_func();
bar_func();
++foo_var;
--bar_var;
foo_func();
bar_func();
return 0;
}

The declaration "extern int foo_var;" says that "foo_var" is defined
*somewhere else*. If you defined it in the header, you'd get a
definition for each translation unit (.c file) that includes the header.
By defining it in the .c file, and compiling that file only once, you
get just one definition.

If you include the header in multiple files, you'll get multiple
*declarations*, but that's ok as long as there's just one *definition*.

Note that in most cases you're probably better off avoiding global
variables altogether. But if you need them, this is the way to
do it.
 
J

James Kuyper

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?

The problem here is that you're allowed to have no more than one
definition of any variable with external linkage. Actually, you should
avoid having any variables with external linkage - they cause lots of
problems - but if you really feel you need one, then make sure it has no
more than one definition anywhere in your entire program. The purpose of
header files is to share code between multiple translation units. If you
define such a variable in a header file, the variable will be defined
everywhere that you #include that header into.

What you should do is declare the variable in the header file, rather
than defining it. You can do that by using the 'extern' keyword.
However, you should separately define the variable in one and only one
module. You need to #include that header in every part of your program
that uses the variable. You should also #include it wherever the
variable is actually defined, even if the variable is not used it that
part of the program, just so you can get an error message if the
declaration in the header is inconsistent with the definition.

Example:

common.h:
extern int shared_variable;

filea.c:
#include <common.h>
int get_shared(void) {return shared_variable;}

fileb.c:
#include <common.h>
int shared_variable = 5;
 
O

osmium

James Kuyper said:
The problem here is that you're allowed to have no more than one
definition of any variable with external linkage. Actually, you should
avoid having any variables with external linkage - they cause lots of
problems - but if you really feel you need one, then make sure it has no
more than one definition anywhere in your entire program. The purpose of
header files is to share code between multiple translation units. If you
define such a variable in a header file, the variable will be defined
everywhere that you #include that header into.

What you should do is declare the variable in the header file, rather
than defining it. You can do that by using the 'extern' keyword.
However, you should separately define the variable in one and only one
module. You need to #include that header in every part of your program
that uses the variable. You should also #include it wherever the
variable is actually defined, even if the variable is not used it that
part of the program, just so you can get an error message if the
declaration in the header is inconsistent with the definition.

Example:

common.h:
extern int shared_variable;

filea.c:
#include <common.h>
int get_shared(void) {return shared_variable;}

fileb.c:
#include <common.h>
int shared_variable = 5;
 
B

Bill Reid

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.
 
J

Jorgen Grahn

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 ....
you need H-files in C to do the same trick. But that didn't work out
under Borland C 3.1.

Perhaps you know already, but it's worth mentioning: you are using
prehistorical tools. Turbo Pascal was discontinued fifteen years ago,
Borland C++ 3.1 was superceded eighteen years ago. Things have
happened in computing since the early 1990s; you may want to upgrade ...

/Jorgen
 
N

Nick Keighley

tht would be "tubo Pascal". ISO Pascal doesn't have "units" or "uses"

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...

K&R discusses .h files, definition and declaration. You'll still have
to work out how to do it on a particular platform but it gives you the
right framework to work in.
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...

because he wanted to use a variable in more than one module (c-file).
C's way of doing things is not a at all intuitive to someone coming
from another langauge. C is just plain weird, we're just used to it.
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.

Don't you define data types in header files?

my .h files also have #define constants in them.
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

this seems an odd view of the pre-processor
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.

<snip>
 
N

Nick Keighley

Nick Keighley said:
[...]                       You also can use a .h
file to declare data types[...]
Don't you define data types in header files?

Did you miss that or are you making a declare/define distinction for
types?  (The last time *that* came up here, I remember a *very* long
thread!)

I was making the declaration/definition distinction (perhaps
unwisely...). My header files usually contain complete "definitions"
of types.
 
B

Ben Bacarisse

Nick Keighley said:
Nick Keighley said:
[...]                       You also can use a .h
file to declare data types[...]
Don't you define data types in header files?

Did you miss that or are you making a declare/define distinction for
types?  (The last time *that* came up here, I remember a *very* long
thread!)

I was making the declaration/definition distinction (perhaps
unwisely...). My header files usually contain complete "definitions"
of types.

Using the language of the standard, the only thing that can be called a
definition in relation to types is a typedef. This is (as you know) a
declaration that defines an identifier to be a synonym for some other
type. All the ways of introducing new types are just called
declarations. (There may be a few cases where this language is not used
consistently, but, if there are, they must be quite rare).

In short, I think it's reasonable to say that header files declare data
types.

Despite this, I agree with you. I often describe a structure
declaration as a type definition; even going so far as to distinguish
between the "declaration" of an incomplete type, and the "definition" of
a complete one. All this despite knowing that this is not the way they
are referred to in the language specification.

I think it's pretty safe to mess with the words here because there isn't
much scope for misunderstanding. That's quite unlike the declare/define
distinction for objects, which it critical.
 
R

Ruud

Hallo Jorgen,

Things have happened in computing since the early 1990s; you
may want to upgrade ...

A part of my programs only can run under DOS because they emulate old
Commodore floppy drives by using the LPT and a COM port. And
especially the IEC drives, like the 1541 used by the C64 and VIC-20,
are quite time critical. It is for these programs that I still _need_
the older DOS programming tools.
There are programs now that can do the same trick under Windows and
Linux but the efforts that had to be made to make that possible, you
can fill complete libraries with the discussions about it. And at the
end Star Commander (http://sta.c64.org/sc.html) under DOS still
proofed to be the best. At the end that lead to the development of
some hardware like the ZoomFloppy: http://www.go4retro.com/products/zoomfloppy/
In this case a Atmel microcontroller takes care of the timing etc. and
the PC is only used for its nice grahical interface.

I was just on the point to start a new subject but your reply gave me
a handle to ask the question here. I'm familiar with Delphi and its
open source brother Lazarus. For C there exist for example C++ Builder
Visual C. I found a page on Wikipedia,
http://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments#C.2FC.2B.2B
, displaying C++ development tools with GUI etc. But I never heard of
most of them. I'm looking for an open source (if possible) GUI running
under Windows.

What can you (or anybody else) advise me?

Thank you very much!


Groetjes, Ruud Baltissen
www.Baltissen.org
 
K

Keith Thompson

Ben Bacarisse said:
Using the language of the standard, the only thing that can be called a
definition in relation to types is a typedef. This is (as you know) a
declaration that defines an identifier to be a synonym for some other
type. All the ways of introducing new types are just called
declarations. (There may be a few cases where this language is not used
consistently, but, if there are, they must be quite rare).

In short, I think it's reasonable to say that header files declare data
types.

Despite this, I agree with you. I often describe a structure
declaration as a type definition; even going so far as to distinguish
between the "declaration" of an incomplete type, and the "definition" of
a complete one. All this despite knowing that this is not the way they
are referred to in the language specification.

I think it's pretty safe to mess with the words here because there isn't
much scope for misunderstanding. That's quite unlike the declare/define
distinction for objects, which it critical.

My conclusion from the last time we discussed this was that the
Standard's definition of the word "definition", in C99 6.7p5:

A *definition* of an identifier is a declaration for that identifier
that:

-- for an object, causes storage to be reserved for that object;
-- for a function, includes the function body;
-- for an enumeration constant or typedef name, is the (only)
declaration of the identiï¬er.

is tailored to the Standard's own needs. It seems clear (to me,
at least), that

struct foo { int x; };

is a definition of "struct foo" (i.e., it's a declaration that
causes the named entity to exist), but since the Standard doesn't
refer to it as a "definition", the definition of "definition"
doesn't cover it. It can make it a bit difficult to discuss such
things while sticking to the terminology defined by the Standard.
 
T

Tim Rentsch

Keith Thompson said:
My conclusion from the last time we discussed this was that the
Standard's definition of the word "definition", in C99 6.7p5:

A *definition* of an identifier is a declaration for that identifier
that:

-- for an object, causes storage to be reserved for that object;
-- for a function, includes the function body;
-- for an enumeration constant or typedef name, is the (only)
declaration of the identifier.

is tailored to the Standard's own needs. It seems clear (to me,
at least), that

struct foo { int x; };

is a definition of "struct foo" (i.e., it's a declaration that
causes the named entity to exist), but since the Standard doesn't
refer to it as a "definition", the definition of "definition"
doesn't cover it. It can make it a bit difficult to discuss such
things while sticking to the terminology defined by the Standard.

The problem is that

struct foo { int x; };

defines the content of the type, not just the type itself.
In some sense the type is "defined" just by saying

struct foo;

since that declaration causes the type to come in to
existence (ie, in the compiler's symbol table). Whatever
terms we use need to be able to distinguish these two
kinds of "definitions".

For what it's worth, the Standard _does_ say that the
bracket-enclosed list 'defines the content' of the
type in question.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top