[comp.lang.c] How to discriminate the structures?

saito@slb-sdr.UUCP (Naoki Saito) (12/03/87)

	A few weeks ago, there was a discussion on typeof() on this news group.
I would like to use typeof() if someone has a code of that.
What I want to do is to discriminate type of the structured variables.
For example,

typedef struct {
	float x;
	float y;
} POINT;

typedef struct {
	float r;
	float theta;
} POINTR;

foo(point)
     caddr_t *point; /* In fact, I don't know how to declare point here. */
		     /* caddr_t is "character address type" used in Sun. */
{
  if (typeof(*point) == POINT)
    { do something...}
  else if (typeof(*point) == POINTR)
    { do something...}
}

Could someone out there give me some suggestion/advise?

Thanks in advance.

Naoki Saito (saito%slb.sdr.com)
Schlumberger-Doll Research

gwyn@brl-smoke.ARPA (Doug Gwyn ) (12/03/87)

In article <420@slb-sdr.UUCP> saito@slb-sdr.UUCP (Naoki Saito) writes:
>foo(point)
>     caddr_t *point; /* In fact, I don't know how to declare point here. */
>		     /* caddr_t is "character address type" used in Sun. */
>{
>  if (typeof(*point) == POINT)
>    { do something...}
>  else if (typeof(*point) == POINTR)
>    { do something...}
>}

What the above wants is impossible in principle, unless some sort of
"dope vector" is used for parameter passing.  Because dope vectors add
non-negligible overhead, language implementors normally do not resort
to them unless they're forced to.  C is deliberately designed so as
not to require such overhead on most architectures.

There are two alternative approaches; first, with minimal changes to
your example:

	/* ... typedefs unchanged */

	foo(enum {POINT_T, POINTR_T} type, void *point)
	{
		if (type == POINT_T)
			{/* use ((POINT *)point) */}
		else if (type == POINTR_T)
			{/* use ((POINTR *)point) */}
	}

or, what I would actually recommend:

	typedef struct {
		enum {POINT_T, POINTR_T} type;
		union {
			struct {
				float x;
				float y;
			} cartesian;
			struct {
				float r;
				float theta;
			} polar;
		} u;
	} coords;

	foo(coords *point)
	{
		if (point->type == POINT_T)
			{/* use point->u.cartesian.x etc. */}
		else if (point->type == POINTR_T)
			{/* use point->u.polar.r etc. */}
	}

barmar@think.COM (Barry Margolin) (12/04/87)

In article <420@slb-sdr.UUCP> saito@slb-sdr.UUCP (Naoki Saito) writes:
>	A few weeks ago, there was a discussion on typeof() on this news group.
>I would like to use typeof() if someone has a code of that.
>What I want to do is to discriminate type of the structured variables.
>For example,
>
>typedef struct {
>	float x;
>	float y;
>} POINT;
>
>typedef struct {
>	float r;
>	float theta;
>} POINTR;
>
>foo(point)
>     caddr_t *point; /* In fact, I don't know how to declare point here. */
>		     /* caddr_t is "character address type" used in Sun. */
>{
>  if (typeof(*point) == POINT)
>    { do something...}
>  else if (typeof(*point) == POINTR)
>    { do something...}
>}

If typeof existed, it would have to be built into the compiler, it
couldn't be a library subroutine.  And typeof(*point) would be
caddr_t, not POINT nor POINTR.

C doesn't have runtime data type tagging (a particular implementation
could, but a program that depended on it would not be portable).  The
type of a variable is whatever it is declared to be.  Stricly
speaking, a caller of foo() is required to cast his POINT* or POINTR*
parameter to caddr_t*, e.g.

	POINTR this_point;

	foo ((caddr_t *) &this_point);

So even if the data type were passed in the call, it would pass
caddr_t*, not the specific type.

Someone else already responded suggesting passing an additional
argument to foo to discriminate.  An alternative would be to include a
discriminant in your structure, e.g.

	typedef struct {
		enum {xy, rtheta} type;
		union {POINT, /* when type == xy */
		       POINTR} /* when type == rtheta */
	} GENERAL_POINT;

(please excuse any syntax errors, I don't do much C programming).
Then instead of using typeof(point) you use point.type.

---
Barry Margolin
Thinking Machines Corp.

barmar@think.com
seismo!think!barmar

peter@sugar.UUCP (Peter da Silva) (12/05/87)

In article <420@slb-sdr.UUCP>, saito@slb-sdr.UUCP (Naoki Saito) writes:
> foo(point)
> caddr_t *point;
> {
>   if (typeof(*point) == POINT)
>     { do something...}
>   else if (typeof(*point) == POINTR)
>     { do something...}
> }

Alas, but typeof(*point) (if there was such an operation) would be (caddr_t *).

Do this:

typedef struct {
	enum { POINT, POINTR } TYPE;
	union {
		struct {
			float x, y;
		} point;
		struct {
			float r, theta;
		} pointr;
	} DATA;
} THING;

foo(thing)
THING thing;
{
	if(thing.TYPE == POINT)
		do something with thing.DATA.point
	else if(thing.TYPE == POINTR)
		do something with thing.DATA.pointr
}

You have to maintain TYPE yourself.
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.