[net.unix-wizards] is "extern" ambiguous

DBrown@Hi-Multics.ARPA (03/29/84)

From:      Dave Brown <DBrown@Hi-Multics.ARPA>

  There  is  a  difficulty  (I  won't call  it  a  bug)  with the
understanding  that  PCC  and  Lint  have  of  what  "extern" and
"static" mean.
  We have several programs obtained from a Vax site which contain
code like:

  <beginning of file>
  main () {
          extern int proc1();

          ...
          proc1();
          ...
  }

  static proc1() {
          ...
  }
  <end of file>


  PCC and Lint notice the  "extern" declaration and remember that
the  author  has  warned them  that  they  may have  to  issue an
external reference.   They then find  the procedure in  the file,
decide that they can link it  without issuing an external ref for
LD, and quite properly do so.

  Unfortunatly, at this point they seem to have lost track of the
fact  that the  first declaration asserted  something that wasn't
true:  it  claimed that proc1  was a "normal"  external function.
We now see  that proc1 isn't a normal external,  but instead is a
"static" (meaning private) function.
  To quote  the white book,  "..  static variables  and functions
provide a way  to conceal data objects and  any internal routines
that  manipulate  them so  that  other routines  and  data cannot
conflict even inadvertantly."
  For obvious reasons we prefer to have the function declared the
same way (as static) every time,  and have redeclared it that way
so Lint won't complain so loudly.

  This raises two questions:
   (1)  Does  anyone have  a  compiler which  DEMANDS  statics be
predeclared as externs?  (ie, can  we fix the code without making
that a machine- or compiler-specific fix), and
   (2) Are  the Unix(tm) compilers and  Lint correct in accepting
this construct  or should they  be regarding this as  a legal but
non-portable construct?

  --dave (unix hack on a bun) brown
  There  is  a  difficulty  (I  won't call  it  a  bug)  with the
understanding  that  PCC  and  Lint  have  of  what  "extern" and
"static" mean.
  We have several programs obtained from a Vax site which contain
code like:

  <beginning of file>
  main () {
          extern int proc1();

          ...
          proc1();
          ...
  }

  static proc1() {
          ...
  }
  <end of file>


  PCC and Lint notice the  "extern" declaration and remember that
the  author  has  warned them  that  they  may have  to  issue an
external reference.   They then find  the procedure in  the file,
decide that they can link it  without issuing an external ref for
LD, and quite properly do so.

  Unfortunatly, at this point they seem to have lost track of the
fact  that the  first declaration asserted  something that wasn't
true:  it  claimed that proc1  was a "normal"  external function.
We now see  that proc1 isn't a normal external,  but instead is a
"static" (meaning private) function.
  To quote  the white book,  "..  static variables  and functions
provide a way  to conceal data objects and  any internal routines
that  manipulate  them so  that  other routines  and  data cannot
conflict even inadvertantly."
  For obvious reasons we prefer to have the function declared the
same way (as static) every time,  and have redeclared it that way
so Lint won't complain so loudly.

  This raises two questions:
   (1)  Does  anyone have  a  compiler which  DEMANDS  statics be
predeclared as externs?  (ie, can  we fix the code without making
that a machine- or compiler-specific fix), and
   (2) Are  the Unix(tm) compilers and  Lint correct in accepting
this construct  or should they  be regarding this as  a legal but
non-portable construct?

  --dave (unix hack on a bun) brown

gwyn@Brl-Vld.ARPA (03/30/84)

From:      Doug Gwyn (VLD/VMB) <gwyn@Brl-Vld.ARPA>

CC and LINT are behaving properly in regard to "extern" declaration
of a function in the same file as a "static" definition.  The use of
"extern" and "static" has evolved through the years but the current
meaning has been around for a while.  The only remaining debate seems
to be about multiple extern definitions (not declarations), which were
put back into UNIX System V Release 2 because of complaints from sites
that had sloppy code that they didn't want to fix (so I am told).  At
least they also added an option to the loader so we can still get the
warnings if we want them.

Keep in mind that "extern" has AT LEAST three different meanings.
In
	proc()
	{
		extern type func();
		...
it basically means "import".  Using "static" in this context should
generate an error.  Since you get the same meaning in this case without
the "extern" qualifier, it is really just a noise word in this context.

Sorry about that, but let's not try to change the language at this point...

DBrown.CSC_SDO@Hi-Multics.ARPA (04/03/84)

  Hmmn...
  Well, I did phrase that as if I wanted to say "static int foo()"
inside a function, didn't I.
  Perhaps the question should be: can I say
  main() {
	char *p, *capitalize_names();
	...
  }
  static char *capitalize_names(q) char *q; {
          ...

  without *either* static or extern declarations.
  My lint (not unexpectedly) gets upset when I tell it that a function
is both static and external.  I would not expect it to complain if I say
something is "function returning char pointer" and later add the fact
that it's "static".

  So I'll reask the question: does anyone have a compiler which
*requires* a static be declared extern?
  If they do I'll conclude dropping the "extern" in my declaration is
non-portable.
  If they don't, I'll conclude that the use of extern ::= static is the
non-portable construct.

  IN EITHER CASE I CONCLUDE AND PROPOSE THAT THE CONSTRUCT IS LEGAL C,
since at least one standard-conforming C compiler allows it.

  I like C as it stands, too!

  --dave

kvm@basser.SUN (Karlos Mauvtaque) (04/04/84)

no

"extern" always means "externally visible".

extern int	i;

declares an externally visible int with name i, it doesn't matter where
the declaration appears.  remember, the default storage class is "extern"
(section 10.2 of the C reference manual) so this is equivalent to

int	i;

similarly

extern int	poot();

or

int	poot();

declares an externally visible function returning int named poot, the
absence of a function body requires that one appear elsewhere.

the ambiguity is in the C compilers which float around.  some compilers
adopt the "restricted environment" (where the explicit appearance of
"extern" means that storage is allocated elsewhere), some just do
incorrect things.

qwerty@drutx.UUCP (JonesBD) (04/06/84)

I would take exception to your statement that

	extern int i;

	and

	int i;

are equivalent, in that the first declaration reserves no storage for
the variable 'i', while the second declaration does reserve storage
for the variable 'i'.  The extern declaration tells the compiler
that storage for the variable 'i' will be allocated in another module.

chris@basser.SUN (Chris Maltby) (04/08/84)

x

My copy of the C Reference Manual quite clearly states in section 10.

"A C program consists of a sequence of external definitions. An external
definition declares an identifier to have storage class 'extern' (by
default) or perhaps 'static'..."

If your C compiler doesn't do that, then it's WRONG (like most UN*X C
compilers).  Just because your loader is correspondingly broken is no
reason to assume that you have some alternative standard.  

Can the discussion of this rest now.

Chris Maltby
University of Sydney

kvm@basser.SUN (Karlos Mauvtaque) (04/12/84)

<reschs refreshes>

>     IN EITHER CASE I CONCLUDE AND PROPOSE THAT THE CONSTRUCT IS LEGAL C,
>   since at least one standard-conforming C compiler allows it.

So we take all of the bugs in PCC to be legal C?

Try this:

main()
{
	int	(*f)();

	(*f)();
	(**f)();
	f();
	(******f)();
}

What piffle.