From: torek@horse.ee.lbl.gov (Chris Torek)
Newsgroups: comp.lang.c
Subject: Re: Incomplete structure declarations: only within structs?
Date: 8 Oct 1992 01:52:05 GMT
Organization: Lawrence Berkeley Laboratory, Berkeley
Reply-To: torek@horse.ee.lbl.gov (Chris Torek)
NNTP-Posting-Host: 128.3.112.15

In article <eksasB4w165w@cybrspc.UUCP> roy%cybrspc@cs.umn.edu
(Roy M. Silvernail) writes:
>I have a full set of prototypes in a header file, which happened to be
>included before the struct [to which some prototypes pointed] was
>defined.  The compile bombed with "Type mismatch in redeclaration of
>function", even though the declaration and prototype were identical.
>Moving the structure definition to before the prototype cured the
>problem, but it leaves me confused as to why the error occurred.

The compiler was right, if a bit unhelpful: gcc gives a much earlier
and more direct warning message first:

	t.c:1: warning: `struct foo' declared inside parameter list
	t.c:1: warning: its scope is only this definition or declaration,
	t.c:1: warning: which is probably not what you want.

What is going on here?

The ANSI C Standard applies the usual scoping rules to prototypes,
so that

	double v;			/* one `v' */
	int frobozz(int v, int w);	/* a different `v' */

has the `obvious' meaning.  As a perhaps-unfortunate side effect,
consider how the following two code fragments relate:

 ---first fragment---
	void one(int v1, int v2) {
		struct foo { int a, b; } v;

		v.a = v1;
		v.b = v2;
		    .
		    .
		    .
	}

	/* `struct foo' no longer exists and any other `struct foo' in
	   this file is by definition different. */

 ---second fragment---
	void two(struct foo { char *s, *t; } *);

Here the `struct foo' that appears in the prototype for function two()
vanishes at the end of the prototype, just as the local `struct foo'
in function one() vanishes at the function's closing brace.  This seems
emimently reasonable to me: obviously the `struct foo' for two() is
not the same as any `outer' `struct foo' (otherwise we would not have
the contents in braces).

Now, you would expect

	void three(struct foo *);

to refer to an `outer' struct foo---and indeed, if there is such a
struct, it *does*.  But what if there is no such structure?

The rule here, as illustrated in function one(), is that such a name
`springs into existence' for the duration of the current scope.  But
this scope ends at the prototype's closing parenthesis.  Thus, this
`struct foo' can never be referred to again, and any later `struct foo'
is by definition different.  Pointers to different structure types are
themselves different types, and are not assignment compatible.  There
is no longer a name for three()'s argument type, so it is impossible to
construct a compatible argument!  (This holds for function two() as
well, for that matter, but there it somehow seems reasonable.)

Some people feel that ANSI should have made this a special case, so
that structure names that `spring into existence' during a prototype do
so at some outer scope.  (This leaves a question as to exactly *which*
scope.  Were I proposing this myself, I would say `the immediate outer
scope'; I think that would work fairly well.)  The standard does not
say this, however.  Instead, it provides a more general solution.

An empty structure declaration in a fresh scope `clears the way' for a
new definition of that tag it that scope.  (Technically, it inserts an
incomplete definition for that tag at the current scope; a later
definition will complete it, and then any further empty declarations
will have no effect.)  This allows, for instance:

	struct x { double omega; int j; };
	struct y { int a, b, c; };
		    .
		    .
		    .
	void xy(void) {
		struct x;	/* clear a path for a new struct x */
		struct y;	/* clear a path for a new struct y */

		struct x { struct y *yp; };
		struct y { struct x *xp; };
		    .
		    .
		    .
	}

to make sure xy()'s x and y structures point to each other, not to some
`outer' x and y structures.  (Actually, in this example, we only need
one such emtpy declaration, but with more complicated structures, we
might need $n-1$, where $n$ is the total number of structures.  The
number can always be less than $n$, and depending on nesting, clever
ordering may be able to reduce this number further.  But using $n$
emtpy declarations is always safe.)

Now, using this method, we can prototype function three() without having
to define `struct foo' in advance:

	struct foo;			/* make an incomplete "struct foo" */
	void three(struct foo *);	/* and then refer to it */

Thus, while C's straightforward scoping rules lead to a rather useless
effect, the problem is not serious.  Header files can simply declare
structure tags `in advance'.  This has the side effect of making the
header safe (or at least safer) if it is included in something other
than the outermost scope.  In any case, it uses a single special case
---one which would be needed anyway for functions like xy()---rather
than two, which is probably a Good Thing.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov