要在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);
在C中,这会编译为char* a = (char *) malloc(4)
,其中演员阵容是完全不必要的,但在C ++中void *
未被隐式提升为char *
,如果演员阵容不存在则会发出错误。
当我可以在GCC或Clang上使用-std=gnu11
进行编译时,这也是一样,但是当我想将我的代码编译为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;
}
但无论在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;
gcc -E
说这条线扩展得很好:
short a = (_Generic((a), short: (short ), char: (char ), char*: (char *), default: (void *) )) 1; ^
是否有一些我缺少的语法,或者在C中根本不可能使用_Generic
生成强制转换代码?
答案 0 :(得分:3)
不,这是不可能的。 (现在看别人证明我错了!)
在_Generic
表达式中,每个泛型关联都是
type-name : assignment-expression
或
default
: assignment-expression
它不能是类型名称或扩展为类型名称的东西。特别是,尽管在编译时解析了_Generic
表达式,但不是宏。最后的结果总是表达。
而且我不相信还有其他方法可以在标准C中做你想做的事。
答案 1 :(得分:2)
问题是您不能在通用选择中包含部分表达式。可能的解决方法是在其中加入完整的表达式:
#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;
}
答案 2 :(得分:0)
我刚想通了..如果在C中使用Visual C ++,而不是C ++,如果在三元表达式中有两个不相关的非void指针结果类型,则三元表达式的类型是第一个。
这很有用。
所以,在一个角落,我被绘制到我有一堆C代码的地方,我需要在一个宏内部投射一个void *的类型,不应该双重评估...
typedef struct DesiredType { ... } DesiredType;
typedef struct ArbitraryType { ... } ArbitraryType;
ArbitraryType/*void*/* function_to_void_double_eval (void* a)
{
...
}
#if defined(_MSC_VER) && !defined(__cplusplus)
#define MACRO(x) (0 ? (DesiredType*)0 : function_to_avoid_double_eval(x))
#else // assume gcc
use typeof and temporaries in a macro
#endif