jsanders@aecom.UUCP (Jeremy Sanders) (12/16/83)
I never really used typedef much, and was pretty suprised at a limitation in it. When I tried this sort of declaration, I got a whole bunch of errors : typedef struct { newtyp *member; } newtyp; I finally had to do something along these lines typedef struct stupid { struct stupid *member; } newtyp; Any ideas why the compiler can't figure out the original entry? -- Jeremy Sanders {philabs|pegasus|esquire|cucard}!aecom!{sanders|jsanders}
ark@rabbit.UUCP (12/17/83)
Original query: Why doesn't this work: typedef struct { newtyp *link; } newtyp; Answer: C is, in effect, a language designed to be parsed in a single pass. In the example above, the compiler doesn't even know yet that "newtyp" is a type the first time it encounters it, so it can't parse it. The following will work, though: struct newtyp { struct newtyp *link; }; or even: typedef struct foo { struct foo *link; } newtyp; because in each case there are no forward references necessary to work out the meaning of an identifier.
smh@mit-eddie.UUCP (Steven M. Haflich) (12/18/83)
Jeremy Sanders asks why the following produces compilation errors: typedef struct { newtyp *member; } newtyp; Quite simply, newtyp does not become a legitimate type attribute until after the entire declaration statement has been processed. C is a one-pass compiler, and has no way of determining attributes from declarations occurring `later' in the source code. The problem is essentially the same as causes the following to be flagged with an `identifier redeclared' error: x = foo(); ... float foo() { ... } Compilers for languages such as PL1, which place no restriction on the ordering of indentifier declaration and use, necessarily make multiple passes through the source code. Incidentally, typedef occupies a very special place in the C language: Suppose you want to write some sort of preprocessor which parses but does not compile C source code. Assume this preprocessor nevertheless wants to verify syntactic correctness of the source, i.e., it catches syntax errors in its input. (I once wrote a source preprocessor for debugging which implemented execution-time line-number/function/module identification which fit this description -- sort of like the PL1 compile-time `statement' condition -- but a really fancy `C beautifier' would fit the bill.) The obvious way to proceed is to snarf the PCC parser, which is written in Yacc, and replace all the action rules which build the parse trees the compiler will eventually need with action code which does what you want. This guarantees that the reductions executed by your preprocessor are exactly the same as by PCC. Clearly there is no need to bother maintaining a symbol table.... Wrong!!! A typedef changes the `syntax' of the language. Consider the following declaration: static foo; /* foo is a static int */ Then consider: typedef float foo; static foo; /* this does absolutely nothing!!! */ In the first fragment the token foo is parsed as an identifier. In the second, foo is parsed as an attribute, and no identifier is declared. Furthermore, the following is unsyntactic in the first program, but normal usage in the second: static foo bar; As near as I have been able to determine, typedef is the *only* construction in C -- other than the preprocessor, which is hardly a part of the language at all -- which can affect parsing nonlocally in this manner. Have a nice context-free day. Steve Haflich MIT Experimental Music Studio
wolfe@mprvaxa (12/19/83)
Well our best interpretation of typedef is that they are not "known" until AFTER they are completley defined. You are expecting the compiler to know about the name 'newtyp' before you have completely defined the typedef. Structures on the other hand don't seem to have this problem. You can happily reference a structure from inside it's declaration. No, I don't think K & R say anything about this. I think this is life in the world of C. -- Peter Wolfe Microtel Pacific Research ..decvax!microsoft!ubc-vision!mprvaxa!wolfe
guido@mcvax.UUCP (Guido van Rossum) (12/22/83)
(Question was: how to write a typedef for a recursive structure)
I always structure my declarations like this:
typedef struct rec record;
/* Bunch of similar typedefs */
struct rec {
record *p;
/* Etc. */
};
/* Etc. */
ucbesvax.turner@ucbcad.UUCP (12/25/83)
#R:aecom:-31900:ucbesvax:4800031:000:336
ucbesvax!turner Dec 18 14:40:00 1983
It used to be, around here, that you couldn't say
typedef struct you_are_my_type {
...
} you_are_my_type;
i.e., it kept struct/union names in the same name-space as types.
Things seemed to have changed without warning, at least in UC Berkeley
cc. I wonder what the current BTL "standard" is?
---
Michael Turner (ucbvax!ucbesvax)
ldl@genix.UUCP (02/29/84)
typedef struct { newtyp *member; } newtyp; I finally had to do something along these lines typedef struct stupid { struct stupid *member; } newtyp; Jeremy Sanders {philabs|pegasus|esquire|cucard}!aecom!{sanders|jsanders} Unfortunately, just knowing that something is a pointer isn't good enough for C. It insists on knowing 'pointer to what'. (Pascal does allows for the case that knowing that something is a pointer is enough. Something for the new standard?). I'm sure I'll be flamed for this, but, what I do in a case like this is: #define NEWTYP struct newtyp typedef NEWTYP { NEWTYP *member; } newtyp; It does exactly what you 'resorted' to, but is a bit easier (for me) to read. -- Spoken: Larry Landis USnail: 5201 Sooner Trail NW Albuquerque, NM 87120 MaBell: (505)-898-9666 UUCP: {ucbvax,gatech,parsec}!unmvax!genix!ldl
ok@edai.UUCP (Richard O'Keefe) (03/08/84)
Our news system was pruning old articles, where an article was
deemed `old' the instant it arrived, so I missed the start of this.
If my remark duplicates old information I do apologise.
The solution to forward pointers in C is essentially the same as
the solution to forward pointers in Pascal (which does NOT allow
untyped pointers at all, despite the article Re: typedef in C). You
MUST know what a pointer is pointing to, because there are several
machines around where char* and int* have DIFFERENT representations.
What I do is to have somewhere near the front of my foo.h file
typedefs like
typedef struct CELL cellp;
and then put the actual structure or union declarations such as
typedef struct CELL
{
cellp next;
long junk;
} CELL;
anywhere I please. In PASCAL you would have
TYPE
cellp = ^cell;
cell = RECORD
next: cellp;
junk: integer;
END {cell};
Same difference. Perfect clarity with no need for hacky #defines.
tim@unc.UUCP (Tim Maroney) (03/08/84)
I agree that it is too difficult to create recursive structs with a typedef in C. That extra tag that you have to create is a pain: (1) when you're writing C yourself (a phenomenon called "straining programmer creativity") (2) when you're automatically generating C code (for example, for an IDL interface -- you want the generator to be as simple as possible) (3) when you're reading someone else's C code (having two different constructions that mean exactly the same thing is always a bitch) It would be much better if the C compiler would defer creating an error in a typedef for an unknown identifier used as a type, until the types declared in the typedef are known, and perform a fixup then. Unfortunately, this would be fairly difficuly to implement in pcc, since it treats identifiers and typedef names as separate sorts of tokens. Still, that should not be the sort of consideration that shapes a language. -- Tim Maroney, University of North Carolina at Chapel Hill mcnc!unc!tim (USENET), tim.unc@csnet-relay (ARPA) The opinions in this article are entirely my own, and should not be construed as representing the policy of UNC or the opinions of my employers, nor of the race of wombats or any other burrowing quadruped.