[net.lang.c] storage class ambiguity

naftoli@aecom.UUCP (Robert Berlinger) (11/02/83)

There seems to be a slight ambiguity in the description of
external variables in the C reference manual. (The C programming
language, Kernighan & Ritchie, Prentice Hall 1978). To my
knowledge the proper way to declare a global variable is to
declare "int foo;" in one source file and declare "extern int
foo;" in all the rest. However, according to the reference manual
this seems unnecessary and you should be able to declare "int
foo;" in all source files.

The reference page 205, paragraph 10.2 states:

> 10.2 External data definitions
>     An external data definition has the form
>
>		 data-definition:
>			 declaration
>
> The storage class of such data may be extern (which is the
> default) or static, but not auto or register.

According to this, since data outside of a procedure is by default
extern, you need not ever explicitly declare it as such. This is
true in the case of most UN*X compilers that I've seen.  
Example:

		file 1: int foo = 8;
		file 2: int foo;

No errors; foo will be initialized to 8.

		file 1: int foo;
		file 2: int foo = 8;

No errors; foo will be initialized to 8.

		file 1: int foo = 8;
		file 2: int foo = 7;

Multiply defined error from loader.
		
		file 1: extern int foo;
		file 2: extern int foo;

Undefined _foo message from loader.

		file 1: extern int foo = 8;

Compiler msg - cannot initialize external.

The last two errors are the most important here. If extern is
purported to be the default, then why do you get an error if you
state it explicitly? Also, I've heard that IBM/370 compilers do
not resolve the references and will create two seperate global
cells.  If this is true (that not all compilers resolve several
global declarations) then the reference manual should not say
that extern is the default.  Rather, a null storage class outside
of the program definition should mean declaration, and an extern
storage class should mean definition.

Robert Berlinger
Systems Support
Albert Einstein Coll. of Med.

{philabs,esquire,cucard}!aecom!naftoli

john@genrad.UUCP (John Nelson) (11/02/83)

There's no ambiguity here, any compiler that acts that way is WRONG!!!!
		
		file 1: extern int foo;
		file 2: extern int foo;

This should not generate a loader error, The loader is SUPPOSED to
allocate storage for foo.  Unfortunately, sometimes C running under operating
systems other than UNIX use the existing loader, which does not perform
this function.

		file 1: extern int foo = 8;

If the compiler generates an error on this, then it is just plain WRONG!
I cannot emphasize this enough.  The problem is not that the reference
manual should not say that extern is the default storage class, it IS,
and any compiler that does not work this way is not strictly C!


I had a similar problem with the Whitesmith compiler - all externs had to
be initialized (which could be lived with) but also, static's had to be
initialized!  If you have:

		file 1: static int foo;

you get the compiler message: "undeclared static foo".  We don't use
Whitesmiths anymore for this and numerous other non-standard items.

keesan@bbncca.ARPA (Morris Keesan) (11/02/83)

The key to the apparent ambiguity is found on the following page (p. 206) of
Kernighan & Ritchie, in section 11.2, entitled "Scope of externals".  I quote:

	If a function refers to an identifier declared to be extern, then
    somewhere among the files or libraries cnstituting the complete
    program there must be an external definition for the identifier.
				.
				.
				.
	The appearance of the extern keyword in an external definition
    indicates that strage for the identifiers being declared will be
    allocated in another file.  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.  The identifier can be initialized only in the declaration
    where storage is allocated.


    Thus, there is no real ambiguity, and though the storage class of both
types of definition is extern, the distinction is between a definition which
reserves space and one which doesn't.  It is then obviously incorrect for
there to be two declarations without the extern keyword, since space is being
reserved twice, but most compilers/loaders should be able to handle the case
where all the declarations for an external identifier have the extern keyword,
by recognizing the special case of an undefined external, and allotting space
for it, similar to the way Fortran COMMONs are handled when there is no BLOCK
DATA subprogram for them.

keesan@bbncca.ARPA (Morris Keesan) (11/03/83)

-----

This note is to disagree strongly with John Nelson (genrad!john).
I quote alternately from his message and the "C Reference Manual", 
Appendix A of "The C Programming Language", which I take to be the
final arbiter of what is and isn't "strictly C".

Nelson:
-------
>		 file 1: extern int foo;
>		 file 2: extern int foo;
>
>This should not generate a loader error, The loader is SUPPOSED to
>allocate storage for foo.
-----
The loader is NOT supposed to allocate storage, as  per
Kernighan and Ritchie, p. 206:
-----------------------------
 The appearance of the extern keyword in an external definition indicates
 that storage for the identifiers being declared will be allocated in another
 file.  Thus in a multi-file program, an external data definition without the
 extern specifier must appear in exactly one of the files.
-----------

Nelson:
-------
>		 file 1: extern int foo = 8;
>
>If the compiler generates an error on this, then it is just plain WRONG!
>I cannot emphasize this enough.  The problem is not that the reference
>manual should not say that extern is the default storage class, it IS,
>and any compiler that does not work this way is not strictly C!
-----------
When the compiler generates an error on the above, it is behaving RIGHT,
as evidenced by the sentence in Kernighan & Ritchie immediately following
the previous citation.
Kernighan and Ritchie, also p. 206:
-----------------------------------
 The identifier can be initialized only in the declaration where storage is
 allocated.
----------

Nelson:
-------
>I had a similar problem with the Whitesmith compiler - all externs had to
>be initialized (which could be lived with) but also, static's had to be
>initialized!  If you have:
>
>		 file 1: static int foo;
>
>you get the compiler message: "undeclared static foo".  We don't use
>Whitesmiths anymore for this and numerous other non-standard items.
----------

Here I share John Nelson's complaint.  The C compiler for Charles River
Data Systems' UNOS system also requires explicit initialization of statics,
in direct violation of Kernighan & Ritchie, p. 198: "Static and external
variables which are not initialized are guaranteed to start off as 0;"

john@genrad.UUCP (John Nelson) (11/03/83)

GREAT HORNY TOADS!  I was wrong!  I stand corrected.

 /~\
(o o)
| O |   John
 \v/
/---\

notes@ucbcad.UUCP (11/03/83)

#R:aecom:-22300:ucbesvax:4800030:000:355
ucbesvax!turner    Nov  3 02:53:00 1983

Re: john@genrad's comments.

> cat t.c
    extern int foo;
    main() { printf ("%d\n", foo); }
> cat t1.c
    extern int foo;
    f(){}
> cc t.c t1.c
t.c:
t1.c:
Undefined:
_foo

{~ Golly, I guess 4.2bsd cc is just plain WRONG WRONG WRONG. ~}

John, please reread K&R.  I don't think your inference is correct.
---
Michael Turner (ucbvax!ucbesvax.turner)