From: wkaufman@us.oracle.com (William Kaufman)
Newsgroups: comp.lang.c
Subject: Re: Union-initialization portability
Date: 1 Oct 92 21:34:48 GMT
Organization: Oracle Corporation, Redwood Shores CA
X-Disclaimer: This message was written by an unauthenticated user
              at Oracle Corporation.  The opinions expressed are those
              of the user and not necessarily those of Oracle.

In article <1aedrtINN774@gap.caltech.edu> mcs@goblin.caltech.edu (Martin Shepherd) writes:
] 
] typedef enum {FLOAT_PTR, INT_PTR, CHAR_PTR} VarType;
] 
] struct Descriptor {
]   char *name;
]   VarType type;
]   union {
]     void *init;  /* The initialization field of the union */
]     int *iptr;
]     float *fptr;
]     char *cptr;
]   } valof;
] };

[then initializes valof with a (float *), a (char *), and a (float *),
and pulls off the values with:]

]     switch (test[i].type) {
]     case FLOAT_PTR:
]       printf("Variable %s=%f\n", *test[i].valof.fptr);
]       break;
]     case CHAR_PTR:
]       printf("Variable %s=%c\n", *test[i].valof.cptr);
]       break;
]     case INT_PTR:
]       printf("Variable %s=%d\n", *test[i].valof.iptr);
]       break;
]     default:
]       fprintf(stderr, "Unrecognised variable type\n");
]       break;
]     };

] My question: Should this work, given that one is not actually casting
] the void * pointer back to the required type, but simply accessing
] it through union'd members?

    This will fail anywhere that float, int and char pointers are not
all the same as a void pointer.  What's in valof is a (void *): if you
try dereferencing it as anything else, the program may well crash.

] (It does work on a sparc).

    Because Sparcs (and many UNIXes) have only one type of pointer:
there's no way to dereference this the wrong way.  Many non-UNIXes (the
older the more likely) could have a different type for every type of C
construct.  That's one reason (void *) was added: to ensure that a
medium for pointer exchange exists everywhere.

] If not, is
] there another way to achieve this, or should I use a function call
] such as:
] 
]   init_variable(&test[2], "fvar", FLOAT_PTR, &fvar);
] 
] prototyped as:
] init_variable(Descriptor *dsc, const char *name, VarType type, void *valof);
] 
] to cast the 'void *valof' pointer in its argument list to the correct type?

    Well, you could initialize it at run-time (whether by a function
call, or inline code like "test[2].type = FLOAT_PTR; test[2].valof.fptr
= &fvar").  The other choice is to always use a (void *) (assuming all
options for the field are pointers): change your structure to

        struct Descriptor {
          char *name;
          VarType type;
          void *valf;  /* pointer to something-or-other */
        };

and the code to

            switch (test[i].type) {
            case FLOAT_PTR:
              printf("Variable %s=%f\n", *(float *)test[i].valof);
              break;
            case CHAR_PTR:
              printf("Variable %s=%c\n", *(char *)test[i].valof);
              break;
            case INT_PTR:
              printf("Variable %s=%d\n", *(int *)test[i].valof);
              break;
            default:
              fprintf(stderr, "Unrecognised variable type\n");
              break;
            };

Simply, cast to the proper type before dereferencing the (void *).

                                           -- Bill K.

Bill Kaufman,          | "...all conscious species are plastic and
Corporate Lackey       |  all plastic species are conscious."
wkaufman@us.oracle.com |                     -- Yew-Kwang Ng