The union
does not intrinsically store any extra information such as which member was last written. Unless context makes it obvious, you should have another member in the struct
that specifies which member of the union
is used. This may be the purpose of a
in your example, but a member named type
defined as an explicit enum
would make the semantics more obvious (this type of enum
is called a tagged enum). Your function then needs to check for each node which member to use for the minimum computation.
With an extra type
member, the code would look like:
typedef struct A {
union {
int p;
double d;
} pointer;
enum { POINTER_INT = 0, POINTER_DOUBLE } type;
int a;
struct A *next;
} myStruct;
static double get_value(const myStruct *x) {
return x->type == POINTER_DOUBLE ? x->pointer.d : (double)x->pointer.p;
}
myStruct *getMinInList(myStruct *root) {
myStruct *smallest = root;
while (root) {
if (get_value(root) < get_value(smallest)) {
smallest = root;
}
root = root->next;
}
return smallest;
}
If a
has a different purpose, add a type
member with the above semantics.
NOTE: this quick and dirty solution makes the assumption that all values of type int
can be accurately represented in type double
. This would not be the case if both int
and double
are 64 bits. In this case, it is quite cumbersome to compare large integers and doubles that are close to them because the conversion from int
to double
truncates the low order bits. Such truncation can be detected by testing if (int)(double)root->pointer.p == root->pointer.p
. Here is a more elaborate solution for this case, that could be easily adapted any longer integer type:
static double get_value(const myStruct *x, int *adjust) {
if (x->type == POINTER_DOUBLE) {
*adjust = 0;
return x->pointer.d;
} else {
double d = (double)s->pointer.p;
*adjust = x->pointer.p - (int)d;
return d;
}
}
myStruct *getMinInList(myStruct *root) {
myStruct *smallest = root;
while (root) {
int adjust1, adjust2;
double val1 = get_value(root, &adjust1);
double val2 = get_value(smallest, &adjust2);
if (val1 < val2 || (val1 == val2 && adjust1 < adjust2)) {
smallest = root;
}
root = root->next;
}
return smallest;
}