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 **************************************************/