Reputation: 288
I'm using tagged unions in a personal project. As an example, this is the type of code I use:
struct data_unit {
enum {
d_A, d_B, d_C
} dtype;
union {
char a;
int b;
double c;
} data;
};
void print_data(data_unit du) {
switch (du.dtype) {
case d_A: {
printf("%c", du.data.a);
break;
}
case d_B: {
printf("%d", du.data.b);
break;
}
case d_C: {
printf("%lf", du.data.c);
break;
}
default:
break;
}
return;
};
Is there more efficient way to implement print_data
, one without manually checking each case of dtype
? If C allowed lists of types, I would just iterate through it using the enum
, but that isn't an available utility. I need a general way to do this, as I plan on adding a lot of data types to the union.
Is this possible to do? If not, what would a better strategy be for me in this context?
Upvotes: 3
Views: 1496
Reputation: 35164
You could make use of the fact that a pointer to a struct-object may be treated as a pointer to its first member. Hence, when exchanging dtype
and data
, you could access all members in some generic way:
struct data_unit {
union {
char a;
int b;
double c;
} data;
enum {
d_A, d_B, d_C
} dtype;
};
typedef void (print_data_unit) (struct data_unit *du);
void print_data_unit_char(struct data_unit *du) {
printf("%c\n", *((char*)(du)));
}
void print_data_unit_double(struct data_unit *du) {
printf("%lf\n", *((double*)(du)));
}
void print_data_unit_int(struct data_unit *du) {
printf("%d\n", *((int*)(du)));
}
static print_data_unit* functions[3] = { print_data_unit_char, print_data_unit_int, print_data_unit_double };
void print_data(struct data_unit du) {
functions[du.dtype](&du);
}
int main() {
struct data_unit du;
du.dtype = 0;
du.data.a = 'c';
print_data(du);
du.dtype = 1;
du.data.b = 100;
print_data(du);
du.dtype = 2;
du.data.c = 200.55;
print_data(du);
}
Upvotes: 2