[net.lang.c] Forward Referencing of Static Variables OK?

jimpr@tekcbi.UUCP (10/01/85)

A C compiler we are using was designed in such a way that the following
code would not compile:

	extern int thing;	/* don't know yet if thing is static or not */

	main() {
		printf("%d  %d\n", thing, increment(thing));
	}

	static int thing = 0;	/* now we know that it's static */

	int increment(x)
		int x;
	{
		return(++x);
	}

Now the situation is basically this:  the compiler complains because 
"thing" is first declared external int, referenced (as extern int) and
then declared (the designers say "re-declared") static int after the
reference.

Their contention that not allowing this type of forward referencing of
static variables is consistent with "The C Programming Language", (K. & P.).

Now I know this program works quite well on our VAX running 4.2BSD, our
Pyramid running 4.2BSD & System V, and other users say that a few PC's
running Microsoft C and Lattice C are quite happy with this construction.
They all make "thing" static (ie, local to the file "thing" is defined in).

What say you all?  Is there any language in K & P which would dissuade them?
Thanks!

               --Jim Prouty	Tektronix, Inc

uucp:      {ucbvax,decvax,pur-ee,ihnss,chico}!tektronix!tekcbi!jimpr
ARPAnet:   tekcbi!jimpr.tek@rand-relay
CSnet:     tekcbi!jimpr@tek

gwyn@BRL.ARPA (VLD/VMB) (10/04/85)

extern int thing;
...
static int thing = 0;

is perfectly legitimate according to X3J11.
Why waste time trying to relate this to K&R (not K&P).
Point out to your compiler supplier that they're
going to have to fix this anyway.

friesen@psivax.UUCP (Stanley Friesen) (10/04/85)

In article <365@tekcbi.UUCP> jimpr@tekcbi.UUCP writes:
>A C compiler we are using was designed in such a way that the following
>code would not compile:
>
>	extern int thing;	/* don't know yet if thing is static or not */
		.
		.
		.
>	static int thing = 0;	/* now we know that it's static */
>
>Their contention that not allowing this type of forward referencing of
>static variables is consistent with "The C Programming Language", (K. & P.).
>
(Various other compilers are mentioned)
>They all make "thing" static (ie, local to the file "thing" is defined in).
>
>What say you all?  Is there any language in K & P which would dissuade them?
>Thanks!
>
	Well, I cannot find anything explicit in K&R, but the ANSI
Draft Standard fairly clearly indicates that this *is*(or will be)
legal. So any compiler which wants to conform th the std will have
to accept this construct.
-- 

				Sarima (Stanley Friesen)

UUCP: {ttidca|ihnp4|sdcrdcf|quad1|nrcvax|bellcore|logico}!psivax!friesen
ARPA: ttidca!psivax!friesen@rand-unix.arpa

doug@terak.UUCP (Doug Pardee) (10/04/85)

From K&R Appendix A:
  11.2 Scope of externals
   If a function refers to an identifier declared to be extern then
   somewhere... there must be an external [as opposed to static -- dlp]
   definition for the identifier.
   ...
   The appearance of the extern keyword in an external definition
   indicates that storage for the identifiers being declared will be
   allocated in another [as opposed to the current -- dlp] file.

 11.1 Lexical scope
   The lexical scope of identifiers declared in external definitions
   persists from the definition through the end of the source file in
   which they appear.

The problem here is that an "extern" declaration tells the compiler that
the address for the data item (or function) will be supplied by the
link-editor when the program is linked; but the "static" declaration
tells the compiler that the address is "private information" to the
current module.

A system which is smart in this regard could provide a method for the
link-editor to be told that a given address is to be used only within
the current module.  But many systems aren't that "smart" -- it's only
useful for this one case.  A simpler approach is usually used: the
link-editor just isn't told about static variables.
-- 
Doug Pardee -- CalComp -- {calcom1,savax,seismo,decvax,ihnp4}!terak!doug

bc@cyb-eng.UUCP (Bill Crews) (10/05/85)

> extern int thing;
> ...
> static int thing = 0;
> 
> is perfectly legitimate according to X3J11.
> Why waste time trying to relate this to K&R (not K&P).
> Point out to your compiler supplier that they're
> going to have to fix this anyway.

I know you're always (usually?) right, Doug, but this seems to me to be
an ambiguity.  One might have the symbol 'thing' defined in another
module to be linked with this one, and a reference to 'thing' that appears
between the above 'extern' and 'static' might be thought to refer to the
external symbol, since the scope of a static is from the definition point
through the end of the block or source file, depending upon where it is
defined.  Not so?
-- 
  /  \    Bill Crews
 ( bc )   Cyb Systems, Inc
  \__/    Austin, Texas

[ gatech | ihnp4 | nbires | seismo | ucbvax ] ! ut-sally ! cyb-eng ! bc

meissner@rtp47.UUCP (Michael Meissner) (10/05/85)

In article <1893@brl-tgr.ARPA> gwyn@BRL.ARPA (VLD/VMB) writes:
>extern int thing;
>...
>static int thing = 0;
>
>is perfectly legitimate according to X3J11.
>Why waste time trying to relate this to K&R (not K&P).
>Point out to your compiler supplier that they're
>going to have to fix this anyway.
>

Sorry that is wrong.  The only thing that ANSI X3J11 allows is:

	static int thing = 0;

	foo(){
		float thing;

		/*...*/

		{
			extern int thing;	/* refers to static above */
		}
	}

Ie, the first declaration MUST be static.

Michael Meissner, Data General, ...{ihnp4, decvax}!mcnc!rti-sel!rtp47!meissner

brooks@lll-crg.ARpA (Eugene D. Brooks III) (10/05/85)

extern int thing;

static int thing = 3;

main()
{
	int thing = 5;
}

Where is the ambiguity now?

gwyn@BRL.ARPA (VLD/VMB) (10/06/85)

Actually, I no longer remember why I thought that

extern int thing;
...
static int thing = 0;

is legal (according to X3J11).  My reading today is
that the first declaration gives "thing" external
linkage and the second declaration gives it static
linkage, which is a contradictory declaration.  I
think I must have missed the description of linkage
in the X3J11 document when I first looked this up.
My current position is that this is NOT legal usage.
Sorry for the mistake; thanks for pointing it out.

Minow sent me another illustration:

func() {
	extern char *foo();
	...
}
...
static char *foo() { ... }

which my latest attempt at understanding X3J11
tells me is illegal, since without a file-scope
definition in effect, the "extern" forces external
linkage whereas the "static" specifies static
linkage.  In this case, adding

static char *foo();

at the front of the file will keep the "extern"
from having an effect on the linkage type.

K&R is not nearly as thorough in this whole area
as the X3J11 specification, although X3J11 seems
to be compatible with the intent of K&R.

Needless to say, there are a number of compilers
around today that do not enforce these rules.

Programmers:  Declare everything before you use it.
If it is a file-static (private) object/function,
call it "static" whenever you declare it.  If it is
an external (public) object/function, not defined in
the same file, call it "extern".  If it is external
but defined in the same file, you may call it
"extern" in all declarations other than the defining
one.  Don't call anything both "extern" and "static".
(X3J11 is actually more complex than this, but these
rules should keep you out of trouble.)

savage@ssc-vax.UUCP (Lowell Savage) (10/08/85)

> A C compiler we are using was designed in such a way that the following
> code would not compile:

> 	extern int thing;	/* don't know yet if thing is static or not */
> 	main() {...}
> 	static int thing = 0;	/* now we know that it's static */
> 	int increment(x)...
 
> Now the situation is basically this:  the compiler complains because 
> "thing" is first declared external int, referenced (as extern int) and
> then declared (the designers say "re-declared") static int after the
> reference.
> 
> Their contention that not allowing this type of forward referencing of
> static variables is consistent with "The C Programming Language", (K. & P.).

> What say you all?  Is there any language in K & P which would dissuade them?
> Thanks!
>                --Jim Prouty	Tektronix, Inc

From the way I read K&R, the "static" keyword is redundant, unless
it is inside a function.  In other words, "static int thing;" is
equivalent to "int thing;" unless the declaration takes place inside
a function.  (Any comment on that??)

Then, the "extern" keyword specifies that the variable declared is
contained in some other program unit (usually outside the current
function, but in this case, outside the current file).  I have seen
nothing in K&R that says that this variable can be redeclared inside
the current program unit.  In other words, if the compiler writer
wants to be nice, he will let you redeclare it, but he/she does
not have to.  (Any further comments??)

Personally, I would like to be able to do this myself on occasion.
For instance I would like to put the "extern" declaration in an
include file which is included in several source files, and then
"redeclare" it in one of them.  Also, I'd like to have the compiler
then make sure that the two declarations are compatible (so I don't
declare "thing" as a long int in the include file, and as a char in
the code.)  But what we really needed from K&R is a method of declaring
variables outside of functions in include files so that these variables
only need to be declared once.  For instance, if file a.h has the
declaration "int thing;", and a.h is included by b.c and c.c, does
b.c access the same "thing" that c.c does?  I don't think that K&R
specify.  And if the declaration is "extern int thing" then there must
still be a further declaration of "thing" somewhere else.  (Anybody
got anything else to say???)

Sorry it got so long.

				There's more than one way to be savage,

				Lowell Savage

mikeb@inset.UUCP (Mike Banahan) (10/08/85)

The orginal article asked what should happen in this sort of case:

/***********************************/
extern int xxx;

f(){
	xxx = 1;
}

static int xxx;	/* `extra' information about xxx */
/***********************************/

The ANSI committee had a lot of work to do on this one.
There is an even worse issue than that:

/***********************************/
f(){
	{
	extern int xxx;	/* OH BOY!!! - where am I visible? */
			/* Am I really extern? */
	}
}

y(){
	/* can I use xxx in here ???? */
}
/***********************************/

They had to come up with a lot of words to fix that stuff - basically, it
just wan't written down anywhere what was supposed to happen. Bill Plauger
described the whole mess as ``Driving a coach and horses through block
structure.'' The more I look at it, the more I agree.

X3J11 has come up with a set of answers on what should happen. Because
nobody really ``knew'' before, you just get what your compiler happens to
give you. Be warned - it is *highly* nonportable practice, because
different compilers currently do different things. This is one area
where the language was already broken. The standard has chosen one way
of patching it.
-- 
Mike Banahan, Technical Director, The Instruction Set Ltd.
mcvax!ukc!inset!mikeb

twb@hoqam.UUCP (BEATTIE) (10/09/85)

> 
> From the way I read K&R, the "static" keyword is redundant, unless
> it is inside a function.  In other words, "static int thing;" is
> equivalent to "int thing;" unless the declaration takes place inside
> a function.  (Any comment on that??)
> 

In K&R, page 80:
	"An external static variable is known within the remainder
	of the source file in which it is declared, but not in any
	other file"

"Regular" external variables can be declared in one file and
referenced in another thru the "extern" statement.

Tom.
~!{ihnp4|hou2g|allegra|mhuxh}!hoqam!twb
Snacktrek - n. The peculiar habit, when searching for a snack, of
constantly returning to the refrigerator in hopes
that something new will have materialized.

guy@sun.uucp (Guy Harris) (10/10/85)

> From the way I read K&R, the "static" keyword is redundant, unless
> it is inside a function.  In other words, "static int thing;" is
> equivalent to "int thing;" unless the declaration takes place inside
> a function.  (Any comment on that??)

Yup.  How about "wrong"?  11.2 "Scope of externals":

	Identifiers declared "static" at the top level in external
	definitions are not visible in other files.

And identifiers not so declared *are* visible in other files...

	Guy Harris

devine@asgb.UUCP (Robert J. Devine) (10/10/85)

> From the way I read K&R, the "static" keyword is redundant, unless
> it is inside a function.  In other words, "static int thing;" is
> equivalent to "int thing;" unless the declaration takes place inside
> a function.  (Any comment on that??)

  It is not equivalent.  Declaring a variable as "static int abc;"
means that "abc" is not exported to the linker.  "int def;" is exported
and hence can be referenced in other files.  The default storage class
is "extern".

> Then, the "extern" keyword specifies that the variable declared is
> contained in some other program unit (usually outside the current
> function, but in this case, outside the current file).  I have seen
> nothing in K&R that says that this variable can be redeclared inside
> the current program unit.  In other words, if the compiler writer
> wants to be nice, he will let you redeclare it, but he/she does
> not have to.  (Any further comments??)

  To be pedantic, there are two types declarations that are possible
for external variables -- one that defines and one that references.
As an example, what does "extern int abc;" mean in a file?  That is,
is it referencing a definition of "int abc" from a different file?
Or is this where abc is defined?  Difference compilers do different
things in this case.  A portable (?) way of declaring variables that
are used in different files is to have one declaration be the definition.
To do this, initialize it and don't use "extern" in its declaration.

Bob

peter@graffiti.UUCP (Peter da Silva) (10/12/85)

Answer: no. At least not according to the available Ritchie documentation.

> The orginal article asked what should happen in this sort of case:
> 
> /***********************************/
> extern int xxx;
> 
> f(){
> 	xxx = 1;
> }
> 
> static int xxx;	/* `extra' information about xxx */
> /***********************************/
> 
> The ANSI committee had a lot of work to do on this one.

Why? It's perfectly obvious.

The scope of a "global scope" declaration is the entire file after the
declaration. It is not known before the declaration. If the extern keyword
is used, storage is assumed to be allocated elsewhere. If the static
keyword is used, the name is local to the file (useful when building
libraries). The above code is not correct 'C', since xxxx is redeclared.

> There is an even worse issue than that:
> 
> /***********************************/
> f(){
> 	{
> 	extern int xxx;	/* OH BOY!!! - where am I visible? */
> 			/* Am I really extern? */
> 	}
> }
> 
> y(){
> 	/* can I use xxx in here ???? */
> }
> /***********************************/

No. The scope of a declaration within a block is the remainder of the block.
xxx is known within the block, nowhere else.

I don't know about Plauger, but this is all explained in various ancillary
documents to the UNIX programmer's manual.

oleg@birtch.UUCP (Oleg Kiselev x268) (10/16/85)

> From the way I read K&R, the "static" keyword is redundant, unless
> it is inside a function.  In other words, "static int thing;" is
> equivalent to "int thing;" unless the declaration takes place inside
> a function.  (Any comment on that??)
> 
 Yes! "static" means that only the file where the "static <whatever> thing"
 is declared will know about it! It's usefull for doing data hiding and modular
 a la Ada developement ( Thanks to Dan Berry for teaching how to do it right!)

> For instance, if file a.h has the
> declaration "int thing;", and a.h is included by b.c and c.c, does
> b.c access the same "thing" that c.c does?  I don't think that K&R
> specify.  And if the declaration is "extern int thing" then there must
> still be a further declaration of "thing" somewhere else.  (Anybody
> got anything else to say???)

As a matter  of fact!
Yes they do. The linker takes care of resolving this type of reference. If you 
have ever written a linker you'd know!

As long as we are at it : if a.h declares "static <whatever> thing" and is
included by b.c and c.c, b.c and c.c see different things.

And if b.c declares "static <> thing;" and c.c "extern <> thing" linker will
complain about undefined "_c" in c.c!

Also, if you have "extern <> thing" and "static <> thing" static declaration
supercedes the external and is the one seen in the file.

And equivalent "extern" and "auto" declarations are mapped into the same 
location.

And, yes, declaring the same variable two different types is a no-no in the same
file.
> 				Lowell Savage
-- 
-----------------------------------+ With deep indifference,
"I disbelieve an army of invisible |                       Oleg Kiselev.
 mind-flayers!"                    | DISCLAIMER:
"OK. They are *still* not there."  | I don't know what I am talking about and 
-----------------------------------+ therefore am not responsible for any
                                     damages to people who take me seriously!
...!trwrb!felix!birtch!oleg          
...!{ihnp4|randvax}!ucla-cs!uclapic!oac6!oleg


Nothing I ever say reflects the views or opinions of my employers.
They knew who they hired though!

gwyn@BRL.ARPA (VLD/VMB) (10/19/85)

There are several interrelated aspects of "static" and "extern"
due to overloading these keywords.  X3J11 has made a very good
stab at spelling out all the relevant aspects.  Look it up.