[comp.std.c] Multiple typedefs

drew@lethe.UUCP (Drew Sullivan) (04/26/89)

Under ANSI-C the I think that the following is legal:

+------------------------------------------------------------
| #define foo_t	unsigned int		/* from include file 1 */
| extern foo_t foo(void);
| 
| #define foo_t	unsigned int		/* from include file 2 */
| extern foo_t foo(void);
+------------------------------------------------------------

But, is the following legal:

+------------------------------------------------------------
| typedef unsigned int foo_t;		/* from include file 1 */
| extern foo_t foo(void);
| 
| typedef unsigned int foo_t;		/* from include file 2 */
| extern foo_t foo(void);
+------------------------------------------------------------

If it is not legal how do we guard the multiple typedefs.
Do we use #ifdefs, and if so, are there to be any conventions.
-- 
  -- Drew Sullivan, <drew@lethe.uucp>

gwyn@smoke.BRL.MIL (Doug Gwyn) (04/29/89)

In article <2322@lethe.UUCP> drew@lethe.UUCP (Drew Sullivan) writes:
>typedef unsigned int foo_t;		/* from include file 1 */
>extern foo_t foo(void);
>typedef unsigned int foo_t;		/* from include file 2 */
>extern foo_t foo(void);

No, the second typedef is syntactically invalid.
The conventional way to guard against this is:
	#ifndef _FOO_T_DEFINED
	#define	_FOO_T_DEFINED
	typedef unsigned int foo_t;
	#endif
Sorry about that..

rex@aussie.UUCP (Rex Jaeschke) (04/30/89)

> From: gwyn@smoke.BRL.MIL (Doug Gwyn)
> The conventional way to guard against this is:
> 	#ifndef _FOO_T_DEFINED
> 	#define	_FOO_T_DEFINED
> 	typedef unsigned int foo_t;
> 	#endif

Watch out though 'cos this is the solution for implementers. If you 
are Joe Shmoe programmer, you should avoid the leading underscores 
since implementers are permitted to use those names in their headers.

Rex

----------------------------------------------------------------------------
Rex Jaeschke     | C Users Journal     |  Journal of C Language Translation
(703) 860-0091   | DEC PROFESSIONAL    |1810 Michael Faraday Drive, Suite 101
uunet!aussie!rex | Programmers Journal |     Reston, Virginia 22090, USA
----------------------------------------------------------------------------

dave@lethe.UUCP (Dave Collier-Brown) (04/30/89)

In article <2322@lethe.UUCP> drew@lethe.UUCP (Drew Sullivan) writes:
| typedef unsigned int foo_t;		/* from include file 1 */
| extern foo_t foo(void);
| typedef unsigned int foo_t;		/* from include file 2 */
| extern foo_t foo(void);

In article <10167@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
| No, the second typedef is syntactically invalid.
| The conventional way to guard against this is:
| 	#ifndef _FOO_T_DEFINED
| 	#define	_FOO_T_DEFINED
...

  It is interesting that one has to use ifdefs to protect a redefinition
of a typedef but not of a macro.  In P.J. Plauger's column on Standard C [1]
he comments..

	The committee eventually permitted one form of refefinition,
    however. Plum insisted we allow "benign" redefinition of a macro.
    Loosely speaking, a macro definition is benign if it results in
    essentially the same definition as before. Permitting benign
    redefinition, Plum argues, greately simplifiees writing the same
    definition in multiple #include files. (The Standard C library has
    multiple definitions of the macro NULL, for instance.)
 
  Is there a technical reason for the difference in redefinition rules
for macros -vs- typedefs, or is it present for administrative or
historical reasons?  Or is it an error?

--dave c-b
  ps: the above is something close to the meaning of Drew's initial
  question.
-- 
David Collier-Brown,  | {toronto area...}lethe!dave
72 Abitibi Ave.,      |  Joyce C-B:
Willowdale, Ontario,  |     He's so smart he's dumb.
CANADA. 223-8968      |

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/01/89)

In article <16.UUL1.3#5077@aussie.UUCP> rex@aussie.UUCP (Rex Jaeschke) writes:
>Watch out though 'cos this is the solution for implementers.

Yeah, I debated with myself whether or not to put in the leading _
and decided that if I didn't somebody (you, I suppose) would post
a follow-up warning that implementers would need to use an _.
Sigh.

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/02/89)

In article <2402@lethe.UUCP> dave@lethe.UUCP (Dave Collier-Brown) writes:
>  Is there a technical reason for the difference in redefinition rules
>for macros -vs- typedefs, ...?

Yes.

Oh, you want to know what it is?  Well, consider how the compiler is
going to parse a complex declaration containing several typedefs.
How does it know whether you are defining the same typedef a second
time or are just using it to help typedef something else?

There's no analogous problem with #define, due to its unambiguous
syntax that makes it clear what identifier is being defined.

suitti@haddock.ima.isc.com (Stephen Uitti) (05/03/89)

In article <10190@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <2402@lethe.UUCP> dave@lethe.UUCP (Dave Collier-Brown) writes:
>>  Is there a technical reason for the difference in redefinition rules
>>for macros -vs- typedefs, ...?
>
>Yes.
We're waiting... holding our collective breath.
>
>Oh, you want to know what it is?  Well, consider how the compiler is
>going to parse a complex declaration containing several typedefs.
>How does it know whether you are defining the same typedef a second
>time or are just using it to help typedef something else?
>
>There's no analogous problem with #define, due to its unambiguous
>syntax that makes it clear what identifier is being defined.

This is the first good answer i've heard.  I still think it is
a (design) bug, though not by any means a new one.  

Four design options come to mind:

1. Omit typedef from the language.  People will then not be tempted to
   use it.

2. iftypedef(x), untypedef(x), and possibly retypedef(x, y).  Example:
	iftypedef(mode_t) {
		untypedef(mode_t);
		retypedef(mode_t, (char *));
	}

3. Disallow typedef definitions using typedef'ed symbols.  Allow
   typedef foo int;
   typedef foo int;
   to work.

4. Disallow
   typedef foo *foo;
   that is, self-referential typedefs.  Then allow
   typedef foo int;
   typedef foo int;
   to work, or even
   typedef u_int unsigned int;
   typedef foo unsigned int;
   typedef foo u_int;	/* synonym - it is the same */
   to work.

Option 1) is what my choice would have been at the dawn of time
(which is sometime before i knew any C).  Typedef functionality
can be obtained with #defines.  Of course, enums would also be
gone, replaced by #defines.  Option 2) is a hack on a kludge.  In
particular it makes typedef stuff look executable.  Option 3)
doesn't support "complex declarations".  Be real.  Typedefs are
nuisance synonyms that seldom have real use (the UN*X kernel is
one of those "seldom" places - nothing i've ever written outside
the kernel would benefit by them.  The kernel uses them for
simple types for portability reasons - not for itself, but for
its clients).  Option 4) doesn't actually sound too bad.  It is
probably provably completely backwards compatible.

Stephen.
...And my spelling checker agrees, it said "No errors!".

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/03/89)

In article <12937@haddock.ima.isc.com> suitti@haddock.ima.isc.com (Stephen Uitti) writes:
>Option 1) is what my choice would have been at the dawn of time
>(which is sometime before i knew any C).  Typedef functionality
>can be obtained with #defines.

Only in simple cases.  In complicated situations, typedefs are
practically essential.

None of your four options (plus other suggestions X3J11 considered)
struck me as feasible.  Nice try but no cigar.

karl@haddock.ima.isc.com (Karl Heuer) (05/04/89)

In article <10190@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <2402@lethe.UUCP> dave@lethe.UUCP (Dave Collier-Brown) writes:
>>[why are repeated typedefs illegal?]
>
>Well, consider how the compiler is going to parse a complex declaration
>containing several typedefs.  How does it know whether you are defining the
>same typedef a second time or are just using it to help typedef something
>else?

It seems to me that the compiler is going to have to be able to handle such a
case anyway.  Note that
	typedef int foo;
	void f(void) {
	    typedef int foo;
	}
*is* legal (and would be even if the two types didn't match; the second simply
hides the first until end-of-scope).  At the point of the second declaration,
the compiler has to be prepared for both a redeclaration of foo and a new
declaration using foo.  Given a compiler that can parse this, it would seem
that the extra effort to handle the desired feature would be negligible.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

corbett@beatnix.UUCP (Bob Corbett) (05/06/89)

In article <12955@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
!It seems to me that the compiler is going to have to be able to handle such a
!case anyway.  Note that
!	typedef int foo;
!	void f(void) {
!	    typedef int foo;
!	}
!*is* legal (and would be even if the two types didn't match; the second simply
!hides the first until end-of-scope).

The latest draft of the standard I have (December 7, 1988) does not allow a
storage-class-specifier (in this case typedef) in a struct-declaration-list.
If X3J11 added this feature since that draft, we need another round of public
review.

!Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

					    Faithfully yours,
					    Bob Corbett

diamond@diamond.csl.sony.junet (Norman Diamond) (05/08/89)

In article <12937@haddock.ima.isc.com> suitti@haddock.ima.isc.com (Stephen Uitti) writes:

>Four design options come to mind:

>1. Omit typedef from the language.  People will then not be tempted to
>   use it.
>Option 1) is what my choice would have been at the dawn of time
>(which is sometime before i knew any C).  Typedef functionality
>can be obtained with #defines.  Of course, enums would also be
>gone, replaced by #defines.

Option 1) was in fact the case at the dawn of time.  The C community
discovered that this was one of the things that Pascal did right, and
it was copied (clumsily) into C.

>2. iftypedef(x), untypedef(x), and possibly retypedef(x, y).  Example:
>	iftypedef(mode_t) {
>		untypedef(mode_t);
>		retypedef(mode_t, (char *));
>	}
>Option 2) is a hack on a kludge.  In particular it makes typedef stuff
>look executable.

That's exactly true.  These kinds of operations are expected more at the
preprocessing stage.  If you can design some preprocessing directives
that would handle this problem correctly and not be too difficult to
implement, you might get it into C-0X  (the next standard after C-89).

>3. Disallow typedef definitions using typedef'ed symbols.  Allow
>   typedef foo int;
>   typedef foo int;
>   to work.
>Option 3) doesn't support "complex declarations".

typedef definitions using typedef'ed symbols really are important.
Anyway, gcc does allow duplicate typedefs if they match (warning about
shadows instead of giving an error).  So complex declarations can still
be permitted, and shadows can still be allowed.  Any vendor who has
trouble with these could perhaps distribute gcc instead of their own
C compiler.

>4. Disallow
>   typedef foo *foo;
>   that is, self-referential typedefs.

Huh?  typedef foo *foo;  is already illegal.  It is self-contradictory,
not just self-referential.

>Then allow
>   typedef foo int;
>   typedef foo int;
>   to work,

as in Option 3) above

>   or even
>   typedef u_int unsigned int;
>   typedef foo unsigned int;
>   typedef foo u_int;	/* synonym - it is the same */
>   to work.

unsigned unsigned x;  does not become a valid declaration, no matter
what you do with typedefs (though it was legal in K&R, again no matter
what you do with typedefs).  What happens next:
typedef signed foo int;  is this equivalent to
typedef signed unsigned int int;

>Be real.

That's good advice.  Take it!

>Typedefs are nuisance synonyms that seldom have real use

This is completely false.

>(the UN*X kernel is one of those "seldom" places

It is one of those "many" places.

>- nothing i've ever written outside the kernel would benefit by them.

So _you_ haven't done any real programming outside the kernel.
Big deal.

--
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.co.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-inventing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?