Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

_Generic to fill some union

Tags:

c

c11

I want to use the C11 _Generic keyword to fill an union according to the static type, like:

typedef union {
    double d;
    long l;
    const char*s;
    void*p;
} ty;

#define make_ty(X) _Generic((X),                        \
                            double: (ty){.d=(X)},       \
                            long: (ty){.l=(X)},         \
                            const char*: (ty){.s=(X)},  \
                            default: (ty){.p=(X)})

ty from_double(double x) { return make_ty(x); }
ty from_string(const char*s) { return make_ty(s); }
ty from_long(long l) { return make_ty(l);}

but this does not compile, e.g. GCC 5.3 gives (with gcc -std=c11 -Wall):

u.c: In function ‘from_double’:
u.c:11:35: error: incompatible types when initializing type ‘const char *’ 
                  using type ‘double’
              const char*: (ty){.s=(X)}, \
                                   ^
u.c:14:41: note: in expansion of macro ‘make_ty’
       ty from_double(double x) { return make_ty(x); }

BTW, using gcc -std=c99 -Wall gives the same error...

Or is _Generic only useful for tgmath.h ?

I thought that _Generic chooses the expression according to the compiler-known type, so the non-sensical (ty){.s=(x)} would be ignored in from_double....

(if that did work, I would be able to "overload" make_ty according the static, compiler-known, type of the argument...)

like image 967
Basile Starynkevitch Avatar asked Feb 23 '16 06:02

Basile Starynkevitch


1 Answers

All branches of _Generic must be valid code, just as much as in something like if (1) { here; } else { there; }. To have a solution you could take it the other way around. Define functions similar to:

inline ty from_double(double x) { return (ty){ .d = x }; }

for all your cases and then have the macro as:

#define make_ty(X) _Generic((X),                     \
                            double: from_double,     \
                            double: from_long,       \
                            ...)(X)

With the visibility through inline compilers are actually able to optimize such code and will usually not pass through calling the function pointer.

like image 125
Jens Gustedt Avatar answered Nov 19 '22 21:11

Jens Gustedt