有没有办法让countof()测试它的参数是否是一个数组?

时间:2017-06-19 02:43:14

标签: c arrays

计算数组中元素数量的经典宏是:

#define countof(a)  (sizeof(a) / sizeof(*(a)))

这个问题是如果参数是指针而不是数组,它会无声地失败。如果a不是数组,是否有一种可移植的方法可以确保此宏仅与实际数组一起使用,产生编译时错误?

编辑:我的问题似乎与此问题重复:Array-size macro that rejects pointers

3 个答案:

答案 0 :(得分:5)

使用非可移植内置函数,这是一个执行静态断言的宏,a是一个数组:

#define assert_array(a) \
     (sizeof(char[1 - 2 * __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))]) - 1)

适用于gccclang。我使用它来使countof()宏更安全:

#define countof(a)  (sizeof(a) / sizeof(*(a)) + assert_array(a))

但我没有这个问题的便携式解决方案。

答案 1 :(得分:1)

在C11中,您可以将_Static_assert_Generic结合使用,但是您还需要提供类型信息,我认为这是一件好事,因为它提供了额外的粒度。您可以根据{em>元素类型以及_Generic中的是否为数组进行断言,并且可以从{ {1}} ...例如:

_Static_assert

这些错误是由以下测试用例产生的,具体取决于您的编译方式:

assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (char[42]){0}"
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (int *){0}"

可以通过定义#define array_type(a, T) _Generic(a, T *: _Generic(&a, T **: 0 \ , default: 1)\ , default: 0) #define assert_array_type(a, T) _Static_assert(array_type(a, T), "expected array of " #T "; got " #a) int main(void) { assert_array_type((int [42]){0}, int); // this should pass # if defined(TEST_POINTER_FAIL) assert_array_type((int * ){0}, int); // this should fail # endif # if defined(TEST_ELEMENT_FAIL) assert_array_type((char[42]){0}, int); // this should fail # endif } 和/或TEST_POINTER_FAIL来观察这两个测试用例,即

  • TEST_ELEMENT_FAIL应该在编译时由于断言是指针而不是数组而导致断言失败。
  • cc -std=c11 -D'TEST_POINTER_FAIL'应该在编译时导致断言失败,因为该数组实际上是cc -std=c11 -D'TEST_ELEMENT_FAIL'的数组,而不是int的数组。

答案 2 :(得分:0)

AFAIK,要使其在> = C11中通用,您只需要Ref作为非标准扩展名即可:

__typeof