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

标签 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))))

第一 block 是允许int/short/long

默认 情况是允许任何指针。

(0 ? (*(v)) : 0) 的目的是在 v 不是指针时导致编译器错误,但不影响生成的代码(hance 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 的每种指针类型,是否有一种方法可以捕获所有类型的指针,而无需评估其他(非指针)值的表达式?

最佳答案

_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

关于c - _Generic 表达式的死分支导致编译器错误 (C11),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27915086/

相关文章:

c# - C#中构造函数的where子句?

c - _Generic 来填充一些 union

c++11 - x86-SSE指令是否具有自动发布获取指令?

支持 C11 的编译器

创建一个文本文件,每次在 C 中运行时名称都会不同

c - 使用 %d 类型转换导致输出不正确的值

c - 匹配算法的运行时优化

c - Pthread代码运行时中途崩溃

swift - 在通用元类型函数中返回具有特定元类型的对象

C# 通用对象函数指针,相同地址?