Different Pointer Types

Steve Watt steve at wattres.UUCP
Thu Mar 8 15:45:54 AEST 1990


In article <31530004 at hpcvia.CV.HP.COM> brianh at 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 at claris.com also works
If you torture your data long enough, it'll eventually confess.



More information about the Comp.lang.c mailing list