我有兴趣编写一个类型验证宏,如果类型不是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 ? ...
)。
这样,来自float
或bool
等其他类型的偶然隐形广告不会引起注意。
理想情况下,这可行。
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
的每种指针类型是否有一种方法可以捕获所有类型的指针,而无需为其他(非指针)值计算表达式?
答案 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
。