I have a union type declared as follows:
typedef union Data {
int i;
char c;
double d;
float f;
} data;
I know fields are overwritten by new values. I would like to know if there is any way to do the following instead of needing to manually access each field depending on the type of data I want to store:
data *c;
*c = 3; // instead of c.i = 3; c.i should be 3
*c = 'a' // instead of c.c = 'a'; c.c should be 'a', c.i should no longer be 3;
I tried doing as written above, but I get an error saying:
Assigning to 'data' (aka 'union Data') from incompatible type 'int'.
Is there any way to do this?
CodePudding user response:
No. It's not possible. If you want type switching use _Generic but 'a' is an integer character constant (i.e. type is int
) so you will only find partial success with sample input provided:
#include <stdio.h>
typedef union {
char c;
double d;
float f;
int i;
} data;
#define set(d, v) _Generic((v),\
char: setc,\
double: setd,\
float: setf,\
int: seti\
)((d), (v))
void setc(data d, int v) {
d.c = v;
printf("c = %c\n", d.c);
}
void setd(data d, double v) {
d.d = v;
printf("d = %lf\n", d.d);
}
void seti(data d, int v) {
d.i = v;
printf("i = %d\n", d.i);
}
void setf(data d, float f) {
d.f = f;
printf("f = %f\n", d.f);
}
int main() {
data d = { 0 };
set(d, 'a'); // seti()
set(d, (char) 'c');
set(d, 3.14);
set(d, 1.2f);
set(d, 3);
}
and the resulting output:
i = 97
c = c
d = 3.140000
f = 1.200000
i = 3
CodePudding user response:
Here is an alternative approach with a tagged union and a polymorphic instantiation macro. Note however that 'a'
has type int
in C and char
in C , so it must be cast as (char)'a'
to have type char
in both languages.
#include <stdio.h>
typedef struct {
enum { CHAR, INT, FLOAT, DOUBLE } type;
union {
char c;
int i;
float f;
double d;
};
} data;
#define data(v) _Generic((v), \
char: (data){ .type = CHAR, .c = (v) }, \
int: (data){ .type = INT, .i = (v) }, \
float: (data){ .type = FLOAT, .f = (v) }, \
double: (data){ .type = DOUBLE, .d = (v) })
void print(data x) {
switch (x.type) {
case CHAR: printf("char: '%c'\n", x.c); break;
case INT: printf("int: %d\n", x.i); break;
case FLOAT: printf("float: %gf\n", (double)x.f); break;
case DOUBLE: printf("double: %g\n", x.d); break;
}
}
int main() {
data a = data((char)'a'); // char
data b = data('a'); // int
data c = data(3); // int
data d = data(1.2f); // float
data e = data(3.14); // double
print(a);
print(b);
print(c);
print(d);
print(e);
return 0;
}
Output:
char: 'a'
int: 97
int: 3
float: 1.2f
double: 3.14