Path: utzoo!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!wuarchive!decwrl!sgi!zok!wattres!steve From: steve@wattres.UUCP (Steve Watt) Newsgroups: comp.lang.c Subject: Re: Different Pointer Types Message-ID: <439@wattres.UUCP> Date: 8 Mar 90 05:45:54 GMT References: <31530004@hpcvia.CV.HP.COM> Reply-To: steve@wattres.UUCP (Steve Watt) Organization: Steven Watt, Consultant Lines: 119 In article <31530004@hpcvia.CV.HP.COM> brianh@hpcvia.CV.HP.COM (brian_helterline) writes: +I have a question about the following code. Given a structure like: + +struct FOO { + int type_of_data; + int number_of_elements; + union { + int *int_ptr; + unsigned int *un_int_ptr; + long *long_ptr; + } ptr; + }; + +And a fuction to sum up the elements: + +double sum( struct FOO foo ) +{ [somewhat long broken code omitted, see original article] +} +Here are my questions: + +1) Is the above code ok? (other that typos which I've missed.) No. When a pointer to char is dereferenced, you get a char. ONLY. The summing routine needs to be somewhat uglier... Either the switch statement needs to be inside the summing loop, or create a function that returns double, given a pointer to the data type, and create an array of them. typedef enum { int_data, unsigned_data, long_data } data_type; struct FOO { data_type type_of_data; int number_of_elements; int size_of_element; /* In case you want to get some other weird type */ /* Set to sizeof(data_type) */ union { /* These are not really needed for this set of routines... int *int_ptr; unsigned int *un_int_ptr; long *long_ptr; */ void *void_ptr; } ptr; }; double iptod(void *), uptod(void *), lptod(void *); double (*funcs[])(void *) = { iptod, uptod, lptod }; double sum( struct FOO foo ) { /* Cogito ergo sum? :) */ int i; void *p = foo.ptr.void_ptr; double tmp = 0.0; for (i = 0; i < foo.number_of_elements; i++) { tmp += funcs[foo.type_of_data](p); /* see note below */ p = (char *)p + foo.size_of_element; } /* Non-ANSI compilers would require the noted line to be something like: tmp += (*funcs[foo.type_of_data])(p); Some people may also prefer this. */ return (tmp); } double iptod( void *p ) { return (double) (*(int *)p) ; } double uptod( void *p ) { return (double) (*(unsigned *)p) ; } double lptod( void *p ) { return (double) (*(long *)p) ; } Notice that this code is easy to extend to a new data type: If you need to support snorkelwackers, then change the enum to be: int_data, unsigned_data, long_data, snorkelwacker_data add this prototype: double snorkelwackerptod(void *); /* In the prototypes */ add snorkelwackerptod to the function array, so it looks like iptod, uptod, lptod, snorkelwackerptod and double snorkelwackerptod( void *p ) { return (double) (*((snorkelwacker *)p)->snkwck_data_1); } Tah dah! You can now sum up snorkelwacker data, as well! +2) Is this the best way to handle different types of pointers? I realize + that the above code depends on sizof( char ) == 1. What is a + better way? I am stuck with the struct *AS IS*. The best way is to use C++ :). By the way: sizeof(char) is defined to be 1. +Thanks for any/all help/advice No problem! -- Steve Watt ...!claris!wattres!steve wattres!steve@claris.com also works If you torture your data long enough, it'll eventually confess.