Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10 5/3/83; site bbncca.ARPA Path: utzoo!linus!bbncca!keesan From: keesan@bbncca.ARPA (Morris Keesan) Newsgroups: net.lang.c Subject: Re: forward declared structures Message-ID: <884@bbncca.ARPA> Date: Thu, 2-Aug-84 11:31:10 EDT Article-I.D.: bbncca.884 Posted: Thu Aug 2 11:31:10 1984 Date-Received: Fri, 3-Aug-84 00:13:15 EDT References: <226@siemens.UUCP> Organization: Bolt, Beranek and Newman, Cambridge, Ma. Lines: 69 >I have a question on forward declarations of structures in C. Kernighan and >Ritchie does not answer the question and to me the behavior of the Berkeley >Unix C compiler is without question wrong. To wit: > >struct s *ps; > >main() { > struct s { > int i1, i2; > }; >} >foo() { > ps->i1 = 33; >} > >My question is whether field i1 should be known in foo. In the Berkeley >Compiler, it is known if and only if there is a different struct with a >field i1 declared before main is declared !? If there is such a field, >the type and offset of i1 are correct, otherwise you get an undefined field >reference error. > >I discovered this while implementing a C compiler for a class and wanted to >follow real C instead of the simplification of structures that our professor >recommended. My solution was to say that the declaration of the structure was >exported to the block level of the first use of the forward declaration and >no further. Any better ideas? > >Bill Smith >princeton!siemens!wws Indeed, the Berkeley compiler is behaving incorrectly here, but it's easy to see how the bug crept in. The problem is not with knowing about field i1. That is getting treated correctly. In the example, element i1 is not known in the scope of foo, and if another structure is declared with structure member i1, then i1 is known inside foo. See section 14.1 of the C Reference Manual, which says, "the expression before a -> is required only to be a pointer or an integer. If a pointer, it is assumed to point to a structure of which the name on the right is a member." So if i1 is defined in a scope which foo inherits, then it doesn't matter what the type of ps is. The error here is in allowing the declaration of ps as a pointer to an undeclared structure. Playing with my compiler, descended from the Ritchie PDP-11 C compiler, I discover that I can declare a pointer to a structure whether or not that structure is ever declared, either in the scope of the pointer declaration, in an inner scope, forward, or backward. This is clearly illegal: C Ref. Man. section 8.5: A structure or union specifier of the second form, that is, one of struct identifier { struct-decl-list } union identifier { struct-decl-list } declares the identifier to be the structure tag (or union tag) of the structure specified by the list. A SUBSEQUENT declaration may then use the third form of specifier, one of struct identifier union identifier Structure tags allow definition of self-referential structures; . . . a structure or union may contain a pointer to an instance of itself. Capitalization of SUBSEQUENT is mine. Implicitly within this "subsequent" means subsequent to the "struct identifier {" rather than subsequent to the entire declaration, otherwise structures containing pointers to themselves would not be allowed. It looks like it was too much work to keep track of whether the compiler was in the middle of declaring "struct s", and so in order to allow structures to point to themselves, the compiler writer(s) decided to allow any declaration of "pointer to structure", regardless of whether the structure was yet declared. -- Morris M. Keesan {decvax,linus,ihnp4,wivax,wjh12,ima}!bbncca!keesan keesan @ BBN-UNIX.ARPA