是否可以用C11的_Generic实现GNU C的typeof(x)?

cat*_*cat 7 c generics gcc gnu c11

要在C和C++中编译一些代码,我在以下几个地方使用它:

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

char* a = (typeof(a)) malloc(4);
Run Code Online (Sandbox Code Playgroud)

在C中,这将编译到char* a = (char *) malloc(4)完全不必要的强制转换的位置,但是在C++ void *中不会隐式提升,char *如果不存在强制转换则会发出错误.

当我可以-std=gnu11在GCC或Clang上编译时,这也是一样,但当我想将我的代码编译为ISO C11时呢?我以为我可以用C11 _Generic来实现typeof(x)一些类型:

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

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

  return a;
}
Run Code Online (Sandbox Code Playgroud)

但无论gettype(x)a声明中给出什么类型,

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;
Run Code Online (Sandbox Code Playgroud)

gcc -E 说这条线扩展得很好:

short a = (_Generic((a), short: (short ), char: (char ), char*: (char *), default: (void *) )) 1;                             ^
Run Code Online (Sandbox Code Playgroud)

是否有一些我缺少的语法,或者在C中根本不可能生成使用的强制转换代码_Generic

Lun*_*din 4

问题是通用选择中不能有部分表达式。一种可能的解决方法是在其中放入完整的表达式:

#define cast(from, to) _Generic((from), \
  short:       (short) (to),            \
  char:        (char)  (to),            \
  char*:       (char*) (to),            \
  default:     (void*) (to))

int main (void) {
  short a = cast(a, 1);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)