[comp.lang.c] Help needed with #include problems

john@ntvax.UUCP (05/16/88)

I am using Turboc 1.5 and am having problems linking files. I am writing
a large application (over 64k) and am having trouble breaking up the file.
The question is this, when I #include stdio, stdlib etc in multiple source
modules the compiler and linker have no problems, however, this is not the 
case when i #include my own header files. The compile goes ok but the linker 
gives me the following error - "variable name here" is duplicated in module
"source module name here" . This only occurs for my specfic header files not
the system (stdio, etc). What can I do to get around this problem. Using 
extern may help but the header file is very large. 

Thanks 
john   
convex!ntvax!john

swarbric@tramp.Colorado.EDU (Frank Swarbrick) (05/18/88)

In article <28400001@ntvax> john@ntvax.UUCP writes:
:
:I am using Turboc 1.5 and am having problems linking files. I am writing
:a large application (over 64k) and am having trouble breaking up the file.
:The question is this, when I #include stdio, stdlib etc in multiple source
:modules the compiler and linker have no problems, however, this is not the 
:case when i #include my own header files. The compile goes ok but the linker 
:gives me the following error - "variable name here" is duplicated in module
:"source module name here" . This only occurs for my specfic header files not
:the system (stdio, etc). What can I do to get around this problem. Using 
:extern may help but the header file is very large. 

Variables can only be declaired once without the "extern" keyword.  The
compiler's header files don't include any variables.  That's why they compile
just fine.  Your's shouldn't either, but if you must, do something like this...

----file.c----
#define _FILE
#include <file.h>
int var;
/* do more stuff */
---end file.c---

----file.h----
#ifndef _FILE
extern int var;
#endif
---end file.h---

---file2.c----
#include <file.h>
/* you can now use "var" */
---end file2.c---

Hope this makes some sense...  I also could have sworn you had to do this
with typedefs, but I just tried something and it looks like maybe not.  I
dunno.  You'll have to try it yourself.

Frank Swarbrick (and his cat)           swarbric@tramp.Colorado.EDU
...!{ncar|nbires}!boulder!tramp!swarbric
"We've seen each other's hands.  What else is there?"

mouse@mcgill-vision.UUCP (der Mouse) (05/18/88)

In article <28400001@ntvax>, john@ntvax.UUCP writes:
> I am using Turboc 1.5 and am having problems linking files.  I am
> writing a large application (over 64k) and am having trouble breaking
> up the file.  [...] The compile goes ok but the linker gives me the
> following error - "variable name here" is duplicated in module
> "source module name here".

It sounds as though you have run into the difference between the
"def/ref" model of shared variables and the "common" model.  The
"common" model is the one UNIX has historically used; in this one, a
variable can be defined in multiple files, as long as it is initialized
at most once.  In the "def/ref" model, a variable must be defined
exactly once.  Definition-by-example of terms:

reference	extern int i;
definition	int i;
initialization	int i = 5;

Under UNIX, you could have multiple definitions and the loader would
merge them, provided at most one of them was initialized.  On other
systems (apparently Turbo 1.5 falls into this category), we have the
"def/ref" (definition/reference) model, where only one definition is
permitted and other files must contain merely references.  The K&R
definition of C permits either model; presumably dpANS C does as well,
though you would do well to use just the def/ref model when writing new
code, because it works on both sorts of systems.

Your header file should have externs; each variable must have exactly
one definition, somewhere in one of the C files.  (Which C file defines
which variable doesn't matter from the linker's point of view, though
good style of course says they should be grouped reasonably.  I
generally have one file which contains nothing but variable
definitions.)

					der Mouse

			uucp: mouse@mcgill-vision.uucp
			arpa: mouse@larry.mcrcim.mcgill.edu

dcon@ihlpe.ATT.COM (452is-Connet) (05/19/88)

Several people have commented on the fact of extern...

Here is a method I often use (this was also discussed some
months back).  [I tried to mail it to you, but the mail bounced.)

In the main file I do:

#define GLOBAL
#include "file.h"
#undef GLOBAL /* sometimes */

All other .c files just include file.h

In file.h:

#ifdef GLOBAL
#define EXTERN
#else
#define EXTERN extern
#endif

EXTERN int variable;
(etc)

Now I can have all my variables in one place.
Of course, if you need to initialize variables, that
throws another wrench in the works, but one that can
be handled by the same method.

#ifdef GLOBAL
#define EXTERN
#define INIT(x) = x
#else
#define EXTERN extern
#define INIT(x)
#endif

EXTERN int variable INIT(2);

Hope this helps some (and doesn't open too big a can of worms here!)

Dave Connet
ihnp4!ihlpe!dcon

ljz@fxgrp.UUCP (Lloyd Zusman) (05/21/88)

In article <2955@ihlpe.ATT.COM> dcon@ihlpe.UUCP (David Connet) writes:
 >  ...
 > Here is a method I often use ...
 >  ...
 > In the main file I do:
 > 
 > #define GLOBAL
 > #include "file.h"
 > #undef GLOBAL /* sometimes */
 > 
 > All other .c files just include file.h
 > 
 > In file.h:
 >  ...
 > #ifdef GLOBAL
 > #define EXTERN
 > #define INIT(x) = x
 > #else
 > #define EXTERN extern
 > #define INIT(x)
 > #endif
 > 
 > EXTERN int variable INIT(2);

Here's a slight variation that I use:

#ifdef GLOBAL
#define _ , 	    /* allows you to init multilple values ... see below */
#define EXTERN
#define INIT(x) = { x }	    /* note the braces */
#else
#define EXTERN extern
#define INIT(x)
#endif

EXTERN int variable INIT(2);
EXTERN int array[] INIT( 1 _ 2 _ 3 _ 4 );   /* this works! */

I saw this on the net a year or two ago.

vlcek@mit-caf.UUCP (05/21/88)

People have been asking how to take care of external variables that
must appear in #include files; namely, how does one declare them in
the one file in which they are defined?

The answer I have seen so far is to use #defines to flag to the
#include file whether the current source file contains the variable
definition or merely an external reference.

Perhaps I am missing something, but this seems to me the wrong way to
do things.  For one thing, in a large application, one might need
quite a few #defines to take care of all of the external variables,
which may be interspersed through a number of #include files.  The
target of each #define would then have to be matched with its host
#include file, which the programmer would have to inspect to find out
initialization data, etc, etc.  Good heavens!

I am under the impression that there is nothing wrong with having an
``extern'' reference *and* a variable definition in the source file,
and in fact I have done so in all of my C programming.  So my #include
files contain only ``extern'' references; I declare (and initialize)
the variable in the proper source file, somewhere after the #include
statement.  Putting initialization data for a global variable into an
#include file seems to me almost an act of violence!
-- 
Jim Vlcek
vlcek@caf.mit.edu
!{ihnp4,harvard,seismo,rutgers}!mit-eddie!mit-caf!vlcek

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/21/88)

In article <998@mit-caf.UUCP> vlcek@mit-caf.UUCP (Jim Vlcek) writes:
>Putting initialization data for a global variable into an
>#include file seems to me almost an act of violence!

I don't know about violent, but it's a sure sign of source code out of
control.

markhall@pyramid.pyramid.com (Mark Hall) (05/24/88)

In article <998@mit-caf.UUCP> vlcek@mit-caf.UUCP (Jim Vlcek) writes:

>I am under the impression that there is nothing wrong with having an
>``extern'' reference *and* a variable definition in the source file,
>and in fact I have done so in all of my C programming.  
>-- 
>Jim Vlcek
>vlcek@caf.mit.edu
>!{ihnp4,harvard,seismo,rutgers}!mit-eddie!mit-caf!vlcek

Your practice is OK according to K&R, pg 77:

	There must be only one `definition' of an external variable among
	all the files that make up the source program; other files may
	contain EXTERN declarations to access it.  (There may also
	be an EXTERN declaration in the file containing the definition).

On a related note, it's funny to watch how different compilers react to:
	main() {
		register int a;
		extern   int a;
	}
Some ignore the register directive and map `a' to some global variable
of the same name.  Others ignore the extern directive and create
local references to `a'.  I never could find out from K&R if this was 
an error, or if the `extern' should be ignored, or what.  Can anyone 
comment?  Just the facts, please.

-Mark Hall

ckl@uwbln.UUCP (Christoph Kuenkel) (05/26/88)

In article <998@mit-caf.UUCP>, vlcek@mit-caf.UUCP (Jim Vlcek) writes:
> I am under the impression that there is nothing wrong with having an
> ``extern'' reference *and* a variable definition in the source file,
> and in fact I have done so in all of my C programming.  So my #include
> files contain only ``extern'' references; I declare (and initialize)
> the variable in the proper source file, somewhere after the #include
> statement.  Putting initialization data for a global variable into an
> #include file seems to me almost an act of violence!
I agree totally! Unfortunately, there are many compilers which do not :-(
So regardless what whatever standard or K&R says, its *not* portable.
-- 
Christoph Kuenkel			ck@tub.BITNET
Kantstr. 152				uunet!unido!tub!ck
1000 Berlin 12				{unido,tmpmbx,uwnue,bk35,tub}!uwbln!ckl
West Germany
-- 
Christoph Kuenkel			ck@tub.BITNET
Kantstr. 152				uunet!unido!tub!ck
1000 Berlin 12				{unido,tmpmbx,uwnue,bk35,tub}!uwbln!ckl
West Germany

peter@ficc.UUCP (Peter da Silva) (06/02/88)

In article <7948@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <998@mit-caf.UUCP> vlcek@mit-caf.UUCP (Jim Vlcek) writes:
> >Putting initialization data for a global variable into an
> >#include file seems to me almost an act of violence!
> 
> I don't know about violent, but it's a sure sign of source code out of
> control.

I disagree. It's a good idea to stick your declarations and initialisation
in one place. When you change a variable, or add one, or delete one, you
really need to make sure you get all the declarations. It's much more
convenient if it's all in one place.

But, do it intelligently:

---- foo.h
#ifdef FOO_C
#define GLOBAL
#define INIT(x) =x
#else
#define GLOBAL extern
#define INIT(x)
#endif

GLOBAL char *fooname INIT("foo");
GLOBAL char *footype INIT("program");

#undef GLOBAL
#undef INIT
----

And then:

---- foo.c
#define FOO_C

#include "this.h"
#include "that.h"
#include "foo.h"
#include "the_other.h"
-- 
-- Peter da Silva, Ferranti International Controls Corporation.
-- Phone: 713-274-5180. Remote UUCP: uunet!nuchat!sugar!peter.