[comp.lang.c] Pointing pointers at varying types of objects.

larocque@jupiter.crd.ge.com (David M. LaRocque) (05/02/90)

I am currently involved in translating a large Lisp 
program into C.  Much of the code has already been 
translated by another person and something they did
has me concerned.  Since in Lisp variables are not
typed, any variable can have any Lisp object as its
value.  To deal with this problem my predecessor
wrote code that would perform operations on "generic"
data.

To illustrate, one might have a structure named "employees"
and another named "books".  One would like to have
a balanced binary tree of "employees", and a balanced
binary tree of "books" since one will be searching
for employees and books frequently and independently.  It
is convenient to write the binary tree routines so that
they will operate on any type of data.  To do this a 
pointer to the structure (to be added, deleted,
or searched for) is passed to the routine along with
a function pointer which is used to perform comparisons
among the elements.  This method has worked quite
effectively for this project since we have so many
different types of structures.

My concern is this: on page 44-45 of _C Wizard's Program-
ming Reference_ by W. David Schwaderer he states: "Con-
trary to popular understanding, pointer sizes on some 
machines vary by the type of object pointed to. Moreover,
even if pointer sizes are the same size for different
objects, their internal structure may be different, again
depending on the particular object pointed to.  Hence, 
it is inadvisable to indiscriminately point pointers at
varying types of objects and expect portable or even
correct results."   This is exactly what we are doing.
He goes on to state that not only will this make lint
complain, the following may result in lethal errors:

1. object assignment and referencing including promotion,
   demotion, conversion and sign extension

2. pointer arithmetic (scaling)

3. structure/union member selection

4. evaluation of an expression such as sizeof(ptrx).

We don't perform any of the above operations and so far
haven't had any problems.  The system is running on a
Sun 3.  My question is if I avoid doing the 4 above
operations will I be safe?  Furthermore are there other
issues that I may have overlooked that may compromise
the portability of my system if I use this method?

Thanks for any help,
Dave

/**************************************************
 * larocque@crd.ge.com        (518) 387-5805
 * ...!crdgw1!cetus.crd.ge.com!larocque
 **************************************************/

larocque@jupiter.crd.ge.com (David M. LaRocque) (05/03/90)

In article <7301@crdgw1.crd.ge.com>, larocque@jupiter.crd.ge.com (David M. LaRocque) writes:
> 
> I am currently involved in translating a large Lisp 
> program into C.  Much of the code has already been 
> translated by another person and something they did
> has me concerned.  Since in Lisp variables are not
> typed, any variable can have any Lisp object as its
> value.  To deal with this problem my predecessor
> wrote code that would perform operations on "generic"
> data.

I posted this message earlier today and have gotten the
solution I had hoped for.  Many thanks to Chris Torek
(chris@cs.umd.edu) and for his solution which I am
including (without his permission, but I don't think
he'll mind).

****** Chris' solution start **********************

If you limit yourself to data pointers, you can use `char *' (old C)
or `void *' (ANSI C) as a `generic' pointer type.  The resulting pointers
will always point to `char's or to mystery-objects and must always be
cast to something else before you can use them; this will convert word
pointers or typed pointers on machines that have such.  For instance:

	struct tree {
		struct tree *left;
		struct tree *right;
		void *object;
	};

	void *search(struct tree *top, void *obj, int (*compar)()) {
		int x;
		while (top != NULL) {
			x = (*compar)(top->object, obj);
			if (x == 0)	/* we found it */
				return top->object;
			if (x < 0)	/* top->object < obj: move right */
				top = top->right;
			else		/* top->object > obj: move left */
				top = top->left;
		}
		return NULL;	/* obj not in tree */
	}

then:

	struct myobj {
		int mainval;
		int subval;
		char comment[24];
	};

	int mycompare(void *a1, void *a2) {
		struct myobj *o1 = a1, *o2 = a2;
		if (o1->mainval < o2->mainval)
			return -1;
		if (o1->mainval > o2->mainval)
			return 1;
		if (o1->subval < o2->subval)
			return -1;
		if (o1->subvaxl > o2->subval)
			return 1;
		return 0;	/* equal */
	}
	...
		struct myobj *p;
		if ((p = search(objtree, (void *)&temp, mycompare)) == NULL)
			... not in tree ...
		else
			printf("%.*s\n", sizeof(p->comment), p->comment);

This is not quite as convenient as in Lisp.

Chris

************* End Chris' solution ****************

 
/**************************************************
 * larocque@crd.ge.com        (518) 387-5805
 * ...!crdgw1!cetus.crd.ge.com!larocque
 **************************************************/