cat cat - 1 month ago 10
C Question

Is it possible to implement GNU C's typeof(x) with C11's _Generic?

To make some code compile in C and C++ I use this in a few places:

#ifdef __cplusplus
#define typeof(x) decltype(x) // works ok in most cases, except C++ reference types
#endif

char* a = (typeof(a)) malloc(4);


In C, this compiles to
char* a = (char *) malloc(4)
where the cast is totally unecessary, but in C++
void *
is not implicitly promoted to
char *
and an error is issued if a cast is not present.

This is just as well when I can compile with
-std=gnu11
on GCC or Clang, but what when I want to make my code compile as ISO C11? I thought I could use C11's
_Generic
to implement
typeof(x)
to cast some types:

#define gettype(x) _Generic((x), \
short: (short ), \
char: (char ), \
char*: (char *), \
default: (void *) )

int main (void) {
short a = (gettype(a)) 1;

return a;
}


But no matter what type defined in
gettype(x)
is given in
a
's declaration,

typeof.h: In function ‘main’:
typeof.h:2:24: error: expected expression before ‘,’ token
short: (short ), \
^
typeof.h:8:13: note: in expansion of macro ‘gettype’
char a = (gettype(a)) 1;
^~~~~~~
typeof.h:8:25: error: expected ‘,’ or ‘;’ before numeric constant
char a = (gettype(a)) 1;


gcc -E
says that line expands just fine:

short a = (_Generic((a), short: (short ), char: (char ), char*: (char *), default: (void *) )) 1; ^


Is there some syntax I am missing, or is it simply not possible in C to generate cast code using
_Generic
?

Answer

No, it's not possible. (Now watch someone prove me wrong!)

In a _Generic expression, each generic-association is either

type-name : assignment-expression

or

default : assignment-expression

It can't be a type name or something that expands to a type name. In particular, though a _Generic expression is resolved at compile time, it is not a macro. The final result is always an expression.

And I don't believe there's any other way to do what you want in standard C.