[comp.sys.ibm.pc] Possible Bug in Turbo Linker

forrest@ux1.lbl.gov (Jon Forrest) (11/13/88)

I've been doing some playing around with Turbo C 2.0 and I have
found something that I didn't expect. This is the fact that
if you declare the same external variable in more than one file,
the linker treats them as separate variables instead of treating
them as references to the same variable. You can see this be
creating 2 files, each with "int x" as the first line. Compile
them and link them. You'll see an error message from the linker
saying "Error: x defined in module YYY is duplicated in module ZZZ"
(where YYY and ZZZ are the names of the files). Furthermore, if you
run OBJXREF /RC you see that "_x" exists in both object files
and uses space in both. Another way to prove this is to define
a 60K byte array the same way. Then, when you link, in addition
to getting the error message I mentioned above, you'll also get
an error message complaining about a BSS segment that is greater
than 64K since the two references add up to more than 64K. On the other
hand, if you say "extern int x" in all but one of the files referencing
"x", and then "int x" in just one file, then everything works OK.
Needless to say, this is a pain when such definitions are done in an
#include file.

The reason I think this is wrong, in additon to being different
than the behavior on Unix and VMS, is that K&R (1st edition)
on page 206, section 11.1 says "... all references to the same
external identifier refer to the same object ...". Note that
this is not a flame. If this is the way ANSI C is supposed to
work then this is fine with me, although there will probably
be lots of people who'll end up fighting with this.

The question about the Debugger (either standalone or integrated)
is how to gain control when a null pointer is dereferenced.
The compiler generates a nice check for this but when this happens
the program immediatly exits. I'd like to gain control in the
debugger so that I can find out what went wrong. I didn't see
how to do this in my first reading of the manual.
Jon Forrest		Lawrence Berkeley Lab., 486-4991
forrest@lbl.gov			(internet)
ucbvax!lbl-csam!ux1!forrest	(uucp)
FORREST@LBL			(bitnet)

bobmon@iuvax.cs.indiana.edu (RAMontante) (11/14/88)

(A better answer is probably to be had in comp.lang.c...)

forrest@ux1.lbl.gov (Jon Forrest) writes:

+I've been doing some playing around with Turbo C 2.0 and I have
+found something that I didn't expect. This is the fact that
+if you declare the same external variable in more than one file,
+the linker treats them as separate variables instead of treating
+them as references to the same variable. You can see this be
+creating 2 files, each with "int x" as the first line. Compile
+them and link them. You'll see an error message from the linker
+saying "Error: x defined in module YYY is duplicated in module ZZZ"
+(where YYY and ZZZ are the names of the files). Furthermore, if you
+run OBJXREF /RC you see that "_x" exists in both object files
+and uses space in both.	[...]
+
+The reason I think this is wrong, in additon to being different
+than the behavior on Unix and VMS, is that K&R (1st edition)
+on page 206, section 11.1 says "... all references to the same
+external identifier refer to the same object ...".	[...]

Looking at K&R sections 10 - 11.2, I conclude that Jon's definition of

	int x;

in each file attempts to create an 'x' whose name is available to other
files.  Repeating the definition in other files does not create
additional references to the same external identifier; rather that
creates new externally-available variables with a single, conflicting
name.  In order for a file to _use_ an 'x' that was created/stored in
another file, it must define

        extern int x;

which says that the x *comes from* somewhere external to the file (i.e.,
another file).  Consider this K&R quote, from section 11.2:

   "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."
   [Emphases mine]

So Turbo is in agreement with K&R here, as well as the ANSI draft (I presume).
-- 
--  bob,mon			(bobmon@iuvax.cs.indiana.edu)
-- "I thought it must be one of the prime numbers of the Zeeman Series.
    *I* haven't changed."

dmt@mtunb.ATT.COM (Dave Tutelman) (11/17/88)

In article <1254@helios.ee.lbl.gov> forrest@ux1.lbl.gov (Jon Forrest) writes:
>...
>if you declare the same external variable in more than one file,
>the linker treats them as separate variables instead of treating
>them as references to the same variable. You can see this be
>creating 2 files, each with "int x" as the first line. Compile
>them and link them. You'll see an error message from the linker
>saying "Error: x defined in module YYY is duplicated in module ZZZ"
>(where YYY and ZZZ are the names of the files). 
>.... On the other
>hand, if you say "extern int x" in all but one of the files referencing
>"x", and then "int x" in just one file, then everything works OK.
>
>The reason I think this is wrong, is that K&R (1st edition)
>on page 206, section 11.1 says "... all references to the same
>external identifier refer to the same object ...". 

    Please re-read that section.  It states very clearly:
	"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."
    Turbo is implemented correctly, though I have encountered one
    compiler that takes the more convenient tack you would prefer.
    (Sorry, don't remember which one.)

>Needless to say, this is a pain when such definitions are done in an
>#include file.

    Not necessarily.  My template for an #include file starts with:

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

    Then I use EXTERN (rather than extern) for all external variables
    I define in the header file.  I make sure exactly one of my
    source files contains an early #define MAIN (before my #include).

    Example of definitions in my header file:
	EXTERN int  i;
	EXTERN int  j INIT(3);

    In MAIN, this expands to:	    In other files this expands to:
	int  i;				extern int  i;
	int  j =3;			extern int  j;

Hope this helps.

+---------------------------------------------------------------+
|    Dave Tutelman						|
|    Physical - AT&T Bell Labs  -  Lincroft, NJ			|
|    Logical -  ...att!mtunb!dmt				|
|    Audible -  (201) 576 2442					|
+---------------------------------------------------------------+