[comp.lang.c] global data in C

btb@ncoast.UUCP (Brad Banko) (03/19/88)

In reply to my recent questions, I received a generous number of helpful
replies about the necessity in K&R C to define data storage in one place
and put the extern references in another... i.e., global data must be 
declared differently in two places if you have more than one source file.
apparently, this is true for all C compilers, but it is what K&R says.
perhaps a good extension to C would be a "global" type declaration:
global (data declarator)
which would tell the compiler and linker that the referenced data should
be stored in only one common place.
in the meantime, Tim Olson of AMD posted a very interesting and helpful
trick for adhering to K&R with a minimum of hassle.  (I am trying to do
some GEM/VDI programming on an Atari ST, and so the header files have
a tendency to want to multiply on their own without me having to have
two header files for each set of data.

Anyway, Tim's trick is included below:


From marque!uwmcsd1!uwvax!ames!amdcad!tim  Wed Mar 16 23:41:23 1988
From: uwmcsd1!uwvax!ames!amdcad!tim (Tim Olson)
To: ncoast!btb
Subject: Re: global data in C programming...
Newsgroups: comp.lang.c
In-Reply-To: <7506@ncoast.UUCP>
Organization: Advanced Micro Devices
Cc: 

In article <7506@ncoast.UUCP> you write:
| how does one use global data in C programming?
| i thought that you just create a header file containing the global data
| declarations and then #include it into each of your source files, but
| when i try this (using Mark Williams C on an Atari ST), I get
| a "symbol redefined" message from the linker.
| 
| basically, the type of thing that I am trying to do is:
| 
| x.h:
| 	int i,j;
| 
| x.c:
| #include "x.h"
| 
| xyz() {
| 	i = ...
| }
| 
| y.c:
| #include "x.h"
| 
| zzt() {
| 	i = j ...
| }
| 
| 
| K&R doesn't help me out... the stuff about externs and header files is
| sort of minimal.

There are two types of global data models used in different systems: the
"comm" model and the "def-ref" model.  The comm model occurs in most
UNIX C compilers, while the "def-ref" model is more common in
microcomputer C compilers.

In the "comm" model, whenever a global is declared without an
initializer, it is placed in its own "common block".  The linker
allocates space for this, and fixes up all references to it to point to
the one common block.

In the "def-ref" model, a global is allocated space and given a label by
the assembler.  If two different modules declare a global, then you will
get a multiply-defined identifer error from the linker.

The only way to write portable code is to follow the stricter (def-ref)
model, and, as K&R suggest (11.2) (also read pp 76,77):

	"Thus in a multi-file program, an external data definition
without the 'extern' specifier must appear in exactly one of the files. 
Any other files which wish to give an external definition for the
identifier must include the 'extern' in the definition."

You should write your program like:

x.h:
	extern	int i,j;	/* declare i and j, but don't reserve storage */

x.c:
#include "x.h"

int i, j;	/* define storage for i and j */

xyz() {
	i = ...
}

y.c:
#include "x.h"

zzt() {
	i = j ...
}

If you have a lot of globals, it is sometimes easier to do something like:

x.h:
#ifdef GLOBAL
#define EX
#else
#define EX extern
EX	int i,j;	/* declare i and j, but don't reserve storage */

x.c:
#define GLOBAL	/* all globals declared in this module */
#include "x.h"

xyz() {
	i = ...
}

y.c:
#include "x.h"	/* define the globals, but don't declare them */

zzt() {
	i = j ...
}

Hope this helps....

	-- Tim Olson
	Advanced Micro Devices
	(tim@amdcad.amd.com)



thanks again, tim.


-- 
			Brad Banko
			Columbus, Ohio
			(formerly ...!decvax!cwruecmp!ncoast!btb)
			btb%ncoast@mandrill.cwru.edu

"The only thing we have to fear on this planet is man."
			-- Carl Jung, 1875-1961

flaps@dgp.toronto.edu (Alan J Rosenthal) (03/25/88)

In article <7523@ncoast.UUCP> btb@ncoast.UUCP (Brad Banko) writes:
>perhaps a good extension to C would be a "global" type declaration:
>global (data declarator)
>which would tell the compiler and linker that the referenced data should
>be stored in only one common place.

This was what dmr originally wanted "extern" to mean, which I believe
accounts for the double meanings of "extern" and "static" as they are
used today.

You can see remnants of this idea in the discussion of "extern" in
various places in K&R; for example, it says that extern is the default
storage class for variables declared outside of functions, implying
that "int a" and "extern int a" are the same when written outside of
functions.

The original idea of extern was modified in the face of non-unix
stubborn linkers.

ajr
-- 
If you had eternal life, would you be able to say all the integers?