且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在编译时验证 c/c++ 预处理宏中的参数是否为 ARRAY 类型

更新时间:2023-12-01 07:49:45

这是一个纯 C 的解决方案,它不会调用未定义的行为:

Here's a solution in pure C which invokes no undefined behavior:

#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))

如果您需要确保该值是一个数组(否则会导致编译时错误),您可以简单地将其用作枚举语句(或静态变量)的初始化程序,如下所示:

If you need to ensure that the value is an array (then cause a compile time error if not), you can simply use it as an initializer to an enum statement (or a static variable), like this:

static int __ ## arg ## _is_array = IS_ARRAY(arg); // works for an array, fails for pointer.

我不完全确定 VLA 会发生什么,但稍微尝试一下应该会很快找到答案.

I'm not entirely sure what will happen with VLA's, but playing around a bit should find that answer out rather fast.

旧答案:

由于这被标记为 C(和 GCC),我将在这里尝试一个解决方案:

Since this is tagged C (and GCC), I will attempt a solution here:

#define IS_ARRAY(arg) __builtin_choose_expr(__builtin_types_compatible_p(typeof(arg[0]) [], typeof(arg)), 1, 0)

另一种解决方案,使用 C11 的 _Generic 特性 &typeof:

Another solution, using C11's _Generic feature & typeof:

#define IS_ARRAY(arg) _Generic((arg),
    typeof(arg[0]) *: 0,
    typeof(arg[0]) [sizeof(arg) / sizeof(arg[0])]: 1
)

基本上,它所做的只是使用 GCC 的一些奇特功能来确定参数的类型是否与参数元素类型的数组兼容.它将返回 0 或 1,如果您愿意,您可以将 0 替换为会产生编译时错误的内容.

Basically, all it does is use some fancy features of GCC to determine if the type of the argument is compatible with an array of the type of the argument's elements. It will return 0 or 1, and you could replace the 0 with something that creates a compile time error if you wish.