[comp.std.c] Problem with prototypes and incomplete types

mtr@ukc.ac.uk (M.T.Russell) (02/26/89)

Consider the following code fragment:

	typedef struct object {
		int id;
		void (*destroy)(struct object *);	/* line 3 */
	} object;

	void destroy(object *obj)
	{
		/* destroy the object */
	}

	void f(object *obj)
	{
		(*obj->destroy)(obj);			/* line 13 */
	}

When I compile this with gcc 1.32 (the only ANSI C compiler I have access to)
I get the following:

	obj.c:3: warning: parameter `obj' points to incomplete type
	obj.c: In function f:
	obj.c:13: incompatible types in argument passing

Is gcc right to object to incomplete types in function prototypes?
If so, is there any way to specify the type of a member of a structure
which is a pointer to a function taking a pointer to the structure
as an argument (sorry, I can't think of a better way to phrase this :-)).

One workaround is to declare destroy as

	void (*destroy)(void *);

but this loses type information.

Mark Russell
mtr@ukc.ac.uk

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

In article <237@harrier.ukc.ac.uk> mtr@ukc.ac.uk (M.T.Russell) writes:
>Is gcc right to object to incomplete types in function prototypes?

Logically it might be thought to make a difference.  However, we
once deduced from various constraints scattered throughtout the C
language that "all structure pointers have to smell the same", i.e.
have the same representation.  (Strictly speaking, this assumes the
compiler is not applying global code analysis to identify places
where shortcuts can be applied, so there should be an "as if" in
there somewhere.)  Therefore, the compiler should easily be able to
cope with not knowing the precise structure type in your example.
An incomplete array is similarly no problem.  An incomplete struct
or union parameter (as opposed to a pointer to one) could be more
bothersome, but not noticeably worse than for incomplete data types.

I don't think the pANS disallows an incomplete type in this context.
Certainly the problem is not that the struct tag "object" had
prototype scope, because the scope of the tag had already begun.

>One workaround is to declare destroy as
>	void (*destroy)(void *);

Better in this particular example might be
	void (*destroy)();
so that SOME type checking could still be performed.

I don't recall any public review comments on this, but it's a good
point.  I hope I've interpreted this correctly..