[comp.lang.c] scoping vs linking

ADLER1%BRANDEIS.BITNET@wiscvm.wisc.EDU (11/29/87)

I am very puzzled by the scoping rules in C. I've been looking at some
code which is spread out over several files and which compiles and runs
fine on various systems, including the SUN. In one file we have something
like:

main()
{ .... }

routine1()
{
        int klugec ;
        char **klugev ;

        routine2() ;
        .......

}


In another file we have

routine2()
{
    int i ;
    char *s ;

    ........

    klugev[i++] = s++ ;

    ........

}


Everything works fine. I tried moving routine2 into the first file
to make the file more self-contained and everything fell apart.
The compiler complained that it did not know what klugev is in
routine2. That is understandable, but I don't see what to do about it.
Is there a way to tell routine2 that klugev is the variable introduced
in routine1 ? The scoping rules don't seem to permit this. But then why
did the program work in the first place ? Apparently the linker is
compensating for what looks like a limitation on the expressive power
of C. While I am happy that the linker provides some recourse, at the
same time it bothers me to think that the linker must be taken into
account when writing a C program. The language C is at least the subject
of a proposed ANSI standard whereas I have no information about the
linker.

I am admittedly new at C and my naive comments could well be way off target.
I welcome your comments. I would be particularly interested in knowing how
to bring routine2 into the first file without substantially rewriting the
code.

Thank you.

Sincerely,
ADLER1@BRANDEIS.BITNET

chris@mimsy.UUCP (Chris Torek) (11/30/87)

In article <10575@brl-adm.ARPA> ADLER1%BRANDEIS.BITNET@wiscvm.wisc.EDU writes:
>I am very puzzled by the scoping rules in C.

It is quite simple, actually.  The scope of a variable is the
level at which it was declared, with the restriction that anything
declared `static' cannot be directly referenced from outside the
current file.  In other words:

	int global;		/* scope is global, but code in other files 
				   must use `extern int global' to reference
				   this */
	static int filelocal;	/* code in other files cannot reference
				   this at all */

	f()			/* f is global */
	{
		int v;		/* local to f */
		static int s;	/* local to f and other files cannot
				   reference it, not that they could
				   even without `static'. */
		...
	}

	static
	g()			/* g is local to this file */
	{
		...
	}

While static thus has two meanings (`make it static' and `keep it
to this file'), they never conflict.

>I've been looking at some code which is spread out over several
>files and which compiles and runs fine on various systems, including
>the SUN.

[example deleted due to length; see the parent article]

>Everything works fine.

Then there is something that you omitted from your example;
as it was, it was illegal and would not have compiled on my Sun.

>Is there a way to tell routine2 that klugev is the variable introduced
>in routine1? The scoping rules don't seem to permit this.

That is correct: they do not.  That is, there is no direct analogue
to the Pascal construct

	procedure p;
	var pvar : integer;
		procedure q;
		begin pvar := 4 end;
	begin q end;

There are efficiency reasons not to implement such scoping, and
it is never necessary: it is always possible to pass the shared
variable from p to q.  It may be convenient at times, but C does
not provide it.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/30/87)

In article <10575@brl-adm.ARPA> ADLER1%BRANDEIS.BITNET@wiscvm.wisc.EDU writes:
>routine1()
>{
>        char **klugev ;
>        routine2() ;
>}
>routine2()
>{
>    int i ;
>    char *s ;
>    klugev[i++] = s++ ;
>}
[Example abridged]

>Everything works fine.

It shouldn't have!

>The compiler complained that it did not know what klugev is in routine2.

That is what it should have done in any case.

>Is there a way to tell routine2 that klugev is the variable introduced
>in routine1 ?

The simplest way is to pass it as a parameter to the function.
It could also be moved outside routine1() as a global external datum.
For information on how to do this, read Kernighan & Ritchie.

>But then why did the program work in the first place ?

I doubt that it really "worked".  One contributing factor is that use
of any identifier that has not been previously declared is assumed to
be a reference to an external int datum.  Apparently your linker used
the "common" model and allocated storage for the (undefined) external
int datum klugev.  However, the compiler really should not have
allowed subscripting of it by an integer...  (Never rely on defaults
like this but always declare identifiers before using them.)