[comp.lang.c] question about scope & linkage

cml@giza.cis.ohio-state.edu (Christopher Lott) (08/11/89)

Hi,

I am asking about the scope and declaration of a variable; I have
read K&Rv2, p. 227-228, Scope and Linkage, but can't seem to dig out
the answer.  (what is a 'translation unit' ??)

In the 2 files below, a variable ("twice") is declared, and has space allocated
for it (i think) in both files.  However, the linker does not complain about
a multiply-defined symbol, and the program works just as if one of the
symbols had been prefixed by an "extern" keyword.  As far as I can tell,
what I am doing below is incorrect, but would like to know what is happening
to make it appear to work correctly.

/* text from one.c */
int twice;

main()
{
  twice = 23;
   
  printf("value of twice is %d\n", twice);
  printf("calling function two.\n");
  two();
  printf("value of twice is %d\n", twice);
  printf ("all done.\n");
  return(0);
}

/* text from two.c */
int twice;      /* <- not declared extern */

int two()
{
   printf("value of twice is %d\n", twice);
   printf("resetting twice\n");
   twice = 83;
   return(0);
}

To test this, put the following program text into two files (one.c & two.c),
then type "cc -o one one.c two.c".  No makefile, sorry.

This question cropped up when I noticed that an object was being declared
in a header file ("int j;") and that header file was included by many files.

If the answer is just painfully obvious :-), please email, and I'll repost.
Thanks in advance!

chris...
-=-
cml@cis.ohio-state.edu        Computer Science Dept, OSU          614-292-1826
 or:  ...!{att,pyramid,killer}!osu-cis!cml		<standard disclaimers>

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/11/89)

In article <57257@tut.cis.ohio-state.edu> Christopher Lott <cml@cis.ohio-state.edu> writes:
>(what is a 'translation unit' ??)

A source file and the other files it #includes, directly or indirectly.

>... However, the linker does not complain about a multiply-defined symbol, ...

Yes, that's because your C implementation uses the "COMMON" model for external
object linkage, instead of the "DEF/REF" model described in K&R (1st Edition).
Most UNIX systems are that way.  For portability, you should fix the source so
that there is only one non-"extern" declaration of such an object among all
the translation units that produce the object modules that get linked together.

cpcahil@virtech.UUCP (Conor P. Cahill) (08/11/89)

In article <57257@tut.cis.ohio-state.edu>, cml@giza.cis.ohio-state.edu (Christopher Lott) writes:
> 
> I am asking about the scope and declaration of a variable; I have
> read K&Rv2, p. 227-228, Scope and Linkage, but can't seem to dig out
> the answer.  (what is a 'translation unit' ??)
> 

1. I believe a translation unit is a .c file.
2. Definitions of global data elements:
		real definition:	a declaration with an initialization
		tentative definition:   a declaration without an initialization

A global symbol may have unlimited tentative definitions, but only 1 real
definition.  In other words, you can have "int i;" in every .c and they 
will all refer to the same data space.  You can even have "int i=3;" in 
one (but only one) of the source files and they will still refer to the 
same data space.  But if you have more than one "int i=2;", even if you 
set the initial value to the same value, the loader (ld) will complain 
about multipley defined symbols.

karl@haddock.ima.isc.com (Karl Heuer) (08/12/89)

In article <1001@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>[Stuff about real vs. tentative definitions]  A global symbol may have
>unlimited tentative definitions, but only 1 real definition.

I think you're confusing tentative definitions with non-defining declarations.

>In other words, you can have "int i;" in every .c and they will all refer to
>the same data space.

This is not correct.  A tentative definition retroactively becomes a real
definition if the end of the source file is reached without seeing a real
definition.  The purpose of the tentative-definition nonsense is not to force
the Common-block storage model to work; it's to allow forward reference to
non-global identifiers.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

cpcahil@virtech.UUCP (Conor P. Cahill) (08/12/89)

In article <14270@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes:
> In article <1001@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
> >[Stuff about real vs. tentative definitions]  A global symbol may have
> >unlimited tentative definitions, but only 1 real definition.
> 
> I think you're confusing tentative definitions with non-defining declarations.

I am not.

> 
> >In other words, you can have "int i;" in every .c and they will all refer to
> >the same data space.
> 
> This is not correct.  A tentative definition retroactively becomes a real
> definition if the end of the source file is reached without seeing a real
> definition.  The purpose of the tentative-definition nonsense is not to force
> the Common-block storage model to work; it's to allow forward reference to
> non-global identifiers.
> 

A tentative definition of a data object is not resolved at the end of source
module,  but at link time.  I quote from K&R2 pg 227,

	...In the alternate formulation, which is usual in UNIX systems and
	recognized as a common extension by the Standard, all tentative 
	definitions for an externally linked object, throughout ALL the
	translation units of a program are cosidered together instead of
	in each translation unit separately.  If a definition occurs somewhere
	in the program, then the tentative definitions become merely 
	declarations, but if no definition appears, then all its tentative
	definitions become a definition with initializer 0.


"tentative definition" is defined as "an external object declaration that
does not have an initializer, and does not contain the extern specifier"

Therefore what I said is absolutely correct.  BTW, I don't see how any of
this applies to a "forward reference to non-global identifiers".

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/12/89)

In article <1002@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>	...In the alternate formulation, which is usual in UNIX systems and
>	recognized as a common extension by the Standard, ...

However, note that this "common extension" (so-called because that is
the title of the section of the Standard wherein it is described)
violates the requirements of the Standard.  The "common extensions"
are not in the enforceable part of the Standard, and some of us think
they have no business being printed as an apparent part of the Standard.
(We were outvoted, though; the "Common Extensions" section had political
if not technical value.)

	int i;
at file scope (assuming there is no other file-scope definition for i
in the same translation unit) does reserve storage for i, and it does
have the initial value 0.  A standard-conforming translator is obliged
to enforce this.  Since it also has external linkage, the occurrence
of
	int i = 17;
at file scope in another translation unit directly conflicts with the
0 initializer of the first translation unit.  These rules date back to
the first edition of K&R.

karl@haddock.ima.isc.com (Karl Heuer) (08/14/89)

In article <1002@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>A tentative definition of a data object is not resolved at the end of source
>module,  but at link time.  I quote from K&R2 pg 227 ...

As Doug mentioned, this is a Common Extension, not guaranteed to work on all
conforming implementations.

>BTW, I don't see how any of this applies to a "forward reference to
>non-global identifiers".

Consider a source file that contains
	static int x;
	int f() { return x; }
	static int x = 3;
The third line is the real definition of x; the second line contains a forward
reference to it, which is enabled by the tentative definition on the first
line.  In pre-ANSI C, this was not legal because "static int x;" was a real
definition with implied initializer zero (at least in some linkage models).

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint