_Generic表达式的死分支导致编译器错误(C11)

时间:2015-01-13 04:51:31

标签: c generics c11

我有兴趣编写一个类型验证宏,如果类型不是int / short / long或指针,它只会发出警告。

我遇到的麻烦是指针可以是任何一种指针。

#define INT_OR_POINTER_AS_UINTPTR(v) _Generic((v), \
    signed long:  (uintptr_t)(v),            unsigned long:  (uintptr_t)(v), \
    signed int:   (uintptr_t)(v),            unsigned int:   (uintptr_t)(v), \
    signed short: (uintptr_t)(v),            unsigned short: (uintptr_t)(v), \
    default: (((void)(0 ? (*(v)) : 0),                       (uintptr_t)(v))))

第一个块是允许int/short/long

default的情况是允许任何指针。

如果(0 ? (*(v)) : 0)不是指针,v的意图是导致编译器错误,否则不会影响生成的代码(有0 ? ...)。

这样,来自floatbool等其他类型的偶然隐形广告不会引起注意。

理想情况下,这可行。

int a = 4;
struct Foo *b = NULL;

uintptr_t test_a = INT_OR_POINTER_AS_UINTPTR(a);
uintptr_t test_b = INT_OR_POINTER_AS_UINTPTR(b);

理想情况下,这两种用途都会失败。

float a = 4;
struct Foo b = {0};

uintptr_t test_a = INT_OR_POINTER_AS_UINTPTR(a);
uintptr_t test_b = INT_OR_POINTER_AS_UINTPTR(b);

但是,即使给出int/long/short作为参数,也会评估检查指针的代码并且错误:invalid type argument of unary '*' (have 'int')

无需显式枚举可能传递给此_Generic的每种指针类型是否有一种方法可以捕获所有类型的指针,而无需为其他(非指针)值计算表达式?

1 个答案:

答案 0 :(得分:2)

_Bool是"标准的无符号整数类型",请参见6.2.5,因此如果您需要对此进行特殊处理,则需要单独进行。

否则,您可以使用一个简单的技巧。整数和指针具有对称差异为整数的属性。因此,我们在只能接受整数的上下文中使用对称差异,如数组下标:

#define INT_OR_POINTER_AS_UINTPTR(v) \
             ((sizeof "Allow only integer and pointer types"[(v)-(v)]), (uintptr_t)(v))

对于struct类型,减法将失败,并且浮点类型将产生浮点差异,这不能用于指针运算。

要拒绝_Bool,您可以使用_Generic