gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/13/89)
In article <1567@ubu.warwick.UUCP> geoff@cs.warwick.ac.uk (Geoff Rimmer) writes: >In article <9804@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: >> In article <7488@june.cs.washington.edu> ka@june.cs.washington.edu (Kenneth Almquist) writes: >> >I've been told that incomplete types cannot be used in function prototypes. >> I couldn't find such a prohibition in the pANS. >> (But maybe it's there and I missed it.) >gcc will not allow it: >static void function (struct egg * a); >struct egg { int number1; float number2; }; >static void function (struct egg * a) >{ > printf("In function with [%d,%f]\n",a->number1,a->number2); >} >str.c:1: warning: `struct egg' declared inside parameter list >str.c: In function function: >str.c:6: conflicting types for `function' >str.c:1: previous declaration of `function' >The strange thing is that it doesn't barf on the > struct void function (struct egg *a); >line, even though the structure is as yet undefined. The problem is >when it compares the types of the function's arguments, and sees that >in the call to the function, the argument is type (struct egg *) and >in the declaration it is unknown. >Is this a problem with gcc, or does this happen with all ANSI compilers? Sometimes I wonder if folks in the UK speak the same language. The first warning from GCC is correct: that structure tag "egg" has function prototype scope, and although (I believe) an incomplete type may be used in the declaration, the type must eventually be completed. Once the end of the function declaration is reached it is obviously impossible for that "egg"-tagged structure's type to ever be completed, since the scope of the tag is gone at that point. The "conflicting types" and "previous declaration" warnings are not incorrect: the full type of the first declaration of "function" is unknown due to the earlier problem, whereas the second declaration (part of the function definition) has a definite type. One supposes that that is a mismatch of declaration types. I don't understand what you mean by "doesn't barf ... even though the structure is as yet undefined". That's essentially what the first warning was about. If the whole mess had been preceded by struct egg; then there would have been a structure tag "egg" in scope that would have been taken as the one for the function parameter. It would still be an incomplete type, but one that is in principle possible to complete later in the translation unit (as indeed occurs at the next statement). So far as I have been able to determine, that should be perfectly valid usage. There is nothing inherently "bad" about incomplete types, especially incomplete structure declarations. In fact they are essential for declaring structures that contain pointers to each other.
leo@philmds.UUCP (Leo de Wit) (03/14/89)
In article <9842@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: |There is nothing inherently "bad" about incomplete types, especially |incomplete structure declarations. In fact they are essential for |declaring structures that contain pointers to each other. How essential that is? Consider: struct egg { struct hen { struct egg *eggp; } *henp; }; This declares two structure types, each containing a pointer to the other one. And I can give more complex examples (a nice one is the grammar for the Bourne shell, which can be expressed in these type of recursive data structures: essentially one big struct definition). Leo.
mnc@m10ux.UUCP (Michael Condict) (03/15/89)
In article <976@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes: - In article <9842@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: - |There is nothing inherently "bad" about incomplete types, especially - |incomplete structure declarations. In fact they are essential for - |declaring structures that contain pointers to each other. - - How essential that is? Consider: - - struct egg { - struct hen { - struct egg *eggp; - } *henp; - }; - - This declares two structure types, each containing a pointer to the - other one. And I can give more complex examples ... Yes, but in the example you show, the scope of the "struct hen" tag declaration might be limited to the inside of the "struct egg" declaration, depending on your C compiler and the rules of ANSI-C. Can you show us how to declare these two structs, hen and egg, such that both are guaranteed by the rules of ANSI-C and current C compilers to be accessible after the declaration, without using incomplete types? Even if the above example declares the two tags egg and hen globally, it is awkward and confusing to have to arbitrarily declare one inside the other. It will only lead to very confusing error messages when you try to add another mutually recursive struct declaration and don't get the ordering or the nesting right. Things like struct tags that are global, should be declared only globally, i.e. outside of any function or other struct. By the way, can someone tell me if the above code defines "struct hen" globally in ANSI-C? -- Michael Condict {att|allegra}!m10ux!mnc AT&T Bell Labs (201)582-5911 MH 3B-416 Murray Hill, NJ
throopw@agarn.dg.com (Wayne A. Throop) (03/16/89)
> leo@philmds.UUCP (Leo de Wit) >| gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) >|There is nothing inherently "bad" about incomplete types, especially >|incomplete structure declarations. In fact they are essential for >|declaring structures that contain pointers to each other. > How essential that is? Consider: > struct egg { > struct hen { > struct egg *eggp; > } *henp; > }; Ok. I've considered it. The type "struct egg" is incomplete at the point it is used, namely in the line struct egg *eggp; So I'd say Leo hasn't come up with an example where mutually referential structures can be defined without resorting to incomplete types. As far as I can see, it's still essential. -- All the system's paths must be topologically and circularly interrelated for conceptually definitive, locally transformable, polyhedronal understanding to be attained in our spontaneous -- ergo, most economical -- geodesiccally structured thoughts. --- R. Buckminster Fuller -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw
leo@philmds.UUCP (Leo de Wit) (03/18/89)
In article <884@m10ux.UUCP> mnc@m10ux.UUCP (Michael Condict) writes: |In article <976@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes: [] self-contained cross-referencing struct example omitted ... |Yes, but in the example you show, the scope of the "struct hen" tag declaration |might be limited to the inside of the "struct egg" declaration, depending |on your C compiler and the rules of ANSI-C. There's no such thing as declaration scoped types (if there is I would be very interested to know where you got that information); the scope of struct hen is the same as the scope of struct egg (the same block of whatever). | Can you show us how to |declare these two structs, hen and egg, such that both are guaranteed by the |rules of ANSI-C and current C compilers to be accessible after the declaration, |without using incomplete types? Yes, exactly as it stands. I would be very surprised if (draft) ANSI conformant compilers couldn't handle this. And the C compilers I've seen do treat it correctly. |Even if the above example declares the two tags egg and hen globally, it is |awkward and confusing to have to arbitrarily declare one inside the other. Ah, that's the real problem. Perhaps you're having trouble reading this declaration. As a matter of fact, I have used such declarations more than once (although one doesn't need cross-referencing structures every day), and I never found it awkward nor confusing. The declaration not being symmetrical is more a style issue. |It will only lead to very confusing error messages when you try to add another |mutually recursive struct declaration and don't get the ordering or the nesting |right. Something like this? struct egg { struct hen { struct chicken { struct egg *eggp; } *chickenp; } *henp; }; | Things like struct tags that are global, should be declared only |globally, i.e. outside of any function or other struct. Struct tags? The struct _type_ (nl. struct hen) is what we are discussing (the tag 'henp' is also available being a member of the struct egg, but that's not the point), and as I pointed out before, has the same scope as the struct egg. Leo.
leo@philmds.UUCP (Leo de Wit) (03/18/89)
In article <979@philmds.UUCP> leo@philmds.UUCP (me) writes: |Struct tags? The struct _type_ (nl. struct hen) is what we are .... Forget what I said here. My vocabulary was way off. Leo.