Pointers to Incomplete Types in Prototypes

Steve Summit scs at adam.mit.edu
Fri May 10 12:15:09 AEST 1991


In article <1991May8.072112.20866 at tkou02.enet.dec.com> diamond at jit533.enet@tkou02.enet.dec.com (Norman Diamond) writes:
>In article <1991May8.043353.28983 at athena.mit.edu> scs at adam.mit.edu writes:
>>...there is no meaningful distinction [between struct type
>>"declarations" and "definitions]."
>>...a struct declaration, with or without a tag and with or
>>without a struct-declaration-list, only enters identifier and
>>type information into symbol tables.
>
>And scope and storage class information.  If definitions were distinguished
>from declarations, then the difference would be that declarations don't
>enter type information into the table, and the scope issue might be cloudy.

Structure type definitions/declarations don't have a storage
class.  "Scope information," to my view, is the implicit property
of which (nested) symbol table a given symbol is declared/defined
in, which is of course the whole issue here.

>>There's nothing wrong here.  In the absence of any previous
>>mention of a struct bar,
>>	type foo(struct bar *arg);
>>is as much of a struct "definition" as is
>>	type foo(struct bar { ... } *arg);
>
>No.  The standard says that the presence of "{ ... }" declares the a type.

Well, I hope this doesn't sound like overly-persnickety verbal
nitpicking, but the standard also says things like "A string
literal is a primary expression."  I don't conclude that the
presence of "{...}" is necessarily the only way of declaring a
new type.

>No part of the standard says that "struct bar *" declares a new type.
>"struct bar *" must be a reference.
>
>Now:  The standard allows forward references for structure tags that
>haven't been declared/[defined] yet.  It also allows references to structure
>tags that are declared in outer scopes.  It does not explicitly say that a
>single reference may take advantage of both of these features simultaneously.
>But I think it must be allowed.  There is still no other meaning.

I sort of agree, to the extent that neither analysis can be
conclusively disproved.  To make things clear for everybody,
consider

	struct a *aptr;
	struct a {int a;};

	struct b *bptr;
		{
		struct b {int b;};
		}

		{
		struct c *cptr;
		}
	struct c {int c;};

The declaration of aptr is clearly legal; the following line
completes the incomplete struct a type.  Section 3.5.2.3
discusses this case.

The incomplete struct b type with which bptr is declared is
clearly not completed two lines down.  This, too, is explicitly
stated in section 3.5.2.3 .  (The wording here talks about
"defining the content," so it was not quite correct of me to
suggest that the standard makes no distinction between "declaring"
and "defining" structures.  I'm still not convinced it's a formal
distinction, however.)

The sticky case is the third one.  I don't think that a struct type
can be completed in an outer scope, but the standard doesn't
explicitly say that it can't.  Nor does it say that it can.

>>If mentioning
>>	struct bar *
>>didn't suffice to "define" a struct bar (assuming it wasn't already "defined"),
>
>You betcha!  It doesn't!  RTFS.
>
>>then the one-line translation unit
>>	struct bar *bp;
>>would have to give some kind of an error, much like the "warning:
>>struct bar never defined" which lint issues under the -h option.
>
>I think this might be true.  (Sorry, I'm not in the mood to look it up
>at the moment.)

Well, I was, and I did, and from (still in section 3.5.2.3):

	If a type specifier of the form

		struct-or-union identifier

	occurs prior to the declaration that defines the content,
	the structure or union is an incomplete type.  It
	declares a tag that specifies a type that may be used
	only when the size of an object of the specified type is
	not needed.  If the type is to be completed, another
	declaration of the tag *in the same scope* ... shall
	define the content [emphasis mine].

I concluded that the incomplete declaration, when not followed by
another declaration of the tag in the same scope, was sufficient
to declare a type, as long as that type's size was not needed.
That's why I think that the one-line translation unit

	struct bar *bp;

is conforming, and need elicit no diagnostic.

Since section 3.5.2.3 specifically mentions that a later
declaration in the same scope can complete a struct type (and
the same point is made in the paragraph on incomplete types in
section 3.1.2.5), I am led to believe that it was not the
intention that a declaration in an outer scope be able to do so.

I admit that there may be some ambiguity here.  I had realized
that an interpretation like Norm's was possible while composing
my first reply, and almost mentioned it.  (I hadn't realized
until now that Norm was advancing this interpretation as the way
out of the dissatisfaction.)  To repeat, though, I think that
both interpretations are viable in that neither is explicitly
ruled out.  I leaned the way I did (inner-scope incomplete struct
types aren't completed in outer scopes) because of the "in the
same scope" language, and because I think that's the way
compilers have tended to do it.  (The ones I've written have,
anyway, but I just checked pcc and it seems to, too.)

                                            Steve Summit
                                            scs at adam.mit.edu



More information about the Comp.std.c mailing list