[comp.std.c] pointer to incomplete type?

jejones@mcrware.UUCP (James Jones) (06/04/90)

On computers for which pointers to different types don't have the same format
(the canonical examples, I think, are non-byte-addressable processors),
how can one safely declare a pointer to an incomplete structure, union, or
enumerated type?  (For that last case, the interpretation of "each enumerated
type shall be compatible with an integer type" may make a difference--is that
intended to be

	"for all enumerated types, there exists an integer type such that..."
or	"there exists an integer type such that for all enumerated types,..."?)

	James Jones

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/04/90)

In article <1680@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes:
-how can one safely declare a pointer to an incomplete structure, union, or
-enumerated type?

The type must be complete before any use that depends on it.

-(For that last case, the interpretation of "each enumerated
-type shall be compatible with an integer type" may make a difference--is that
-intended to be
-	"for all enumerated types, there exists an integer type such that..."
-or	"there exists an integer type such that for all enumerated types,..."?)

Each enumerated type is compatible with SOME integer type, but possible
different integer types for different enumerations.  For example, an
enumeration of fewer than 255 members might be implemented using one
byte rather than a full word.

flaps@dgp.toronto.edu (Alan J Rosenthal) (06/06/90)

jejones@mcrware.UUCP (James Jones) writes:
>On computers for which pointers to different types don't have the same format,
>how can one safely declare a pointer to an incomplete structure, union, or
>enumerated type?

I think "struct generic *" will work for structures on all compilers I've heard
of.  Strictly speaking, it's not legal, but I haven't heard of different kinds
of structure pointers having different formats.  Same for unions.

For enumerated types, I don't think you can do it, although, again, they
allocate int space on all compilers I've heard of.

Anyway, except in the case of adding kludges to poorly written code, this
should not be necessary.  Just #include the correct header file, or if the
type definition appears in a .c file, move it into a .h file and #include
it in both .c files.

ajr

karl@haddock.ima.isc.com (Karl Heuer) (06/06/90)

In article <1680@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes:
>On computers for which pointers to different types don't have the same format
>(the canonical examples, I think, are non-byte-addressable processors),
>how can one safely declare a pointer to an incomplete structure...?

I believe it is still true (i.e. one can infer from the Standard) that "all
struct pointers smell the same", precisely because it must be legal to use an
incomplete type in the contexts you're thinking of.  This means that, on such
an architecture, either all structs will be word-aligned (even if they contain
only chars) or else (less likely) all struct pointers will use byte-pointer
format (even if the struct is word-aligned).

(Of course, the as-if rule allows the implementation to play tricks here if
the user can't possibly tell the difference.)

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

steve@groucho.ucar.edu (Steve Emmerson) (06/07/90)

In <13048@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:

>In article <1680@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes:
>-how can one safely declare a pointer to an incomplete structure, union, or
>-enumerated type?

>The type must be complete before any use that depends on it.

Along this line, and in view of expressed, differing opinions on the
subject and my own, subsequent, confusion, I like to post the following
question:

Is the following legal ANSI C?

	In file foo.h:

		typedef struct FooTag	*FooPtr;
		extern FooPtr		FooCreate();
		extern void		FooFree(FooPtr foo);

	In file foo.c:

		#include "foo.h"
		typedef struct FooTag {
		    <complete definition>
		}   FooThing;

		...

		void
		FooFree(FooPtr foo)
		{
		    <destruction code>
		}

The rationale for this is that clients using the "foo" ADT include
"foo.h" and pass variables of type "FooPtr" around but are otherwise
prevented from knowing any details of its implementation (no style 
flames please).

One poster indicated that -- strictly speaking -- this was not legal.
Is this true?  Or does the use of "FooPtr" in a client not depend on
its being a complete type?

Steve Emmerson        steve@unidata.ucar.edu        ...!ncar!unidata!steve

diamond@tkou02.enet.dec.com (diamond@tkovoa) (06/07/90)

In article <7565@ncar.ucar.edu> steve@groucho.ucar.edu (Steve Emmerson) writes:
>In <13048@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>>In article <1680@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes:
>>>how can one safely declare a pointer to an incomplete structure, union, or
>>>enumerated type?
>>The type must be complete before any use that depends on it.

Doug Gwyn didn't exactly answer James Jones' question.  Thus Steve
Emmerson's confusion:

>	In file foo.h:
>		typedef struct FooTag	*FooPtr;
>		extern FooPtr		FooCreate();
>		extern void		FooFree(FooPtr foo);

This will work, because clients use only pointers.  A pointer type
is complete, even if the pointed-to type is not complete yet.
If clients try to use *FooCreate() or FooCreate()->someMember,
or if there is a declaration FooOp(struct FooTag someFoo),
then clients will get in trouble because the struct type is incomplete.

>The rationale for this is that clients using the "foo" ADT include
>"foo.h" and pass variables of type "FooPtr" around but are otherwise
>prevented from knowing any details of its implementation (no style 
>flames please).

This is a perfectly reasonable thing to do.  Now, what kind of goof are
you, resorting to begging "no style flames please" instead of using clear
arguments to properly justify this approach?  ( :-) Teasing only.)

-- 
Norman Diamond, Nihon DEC     diamond@tkou02.enet.dec.com
Proposed group comp.networks.load-reduction:  send your "yes" vote to /dev/null.

bxw@ccadfa.adfa.oz.au (Brad Willcott) (06/07/90)

What about "void *".  Then the pointer can be used to point to anything.  All
you have to do is type cast it when you need it.  Or am I way off base? :-)

-- 
Brad Willcott,                          ACSnet:     bxw@ccadfa.cc.adfa.oz
Computing Services,                     Internet:   bxw@ccadfa.cc.adfa.oz.au
Australian Defence Force Academy,       UUCP:!uunet!munnari.oz.au!ccadfa.oz!bxw
Northcott Dr. Campbell ACT Australia 2600  +61 6 268 8584  +61 6 268 8150 (Fax)