[net.lang.c] typedef in c

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.