计算数组中元素数量的经典宏是:
#define countof(a) (sizeof(a) / sizeof(*(a)))
这个问题是如果参数是指针而不是数组,它会无声地失败。如果a
不是数组,是否有一种可移植的方法可以确保此宏仅与实际数组一起使用,产生编译时错误?
编辑:我的问题似乎与此问题重复:Array-size macro that rejects pointers
答案 0 :(得分:5)
使用非可移植内置函数,这是一个执行静态断言的宏,a
是一个数组:
#define assert_array(a) \
(sizeof(char[1 - 2 * __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))]) - 1)
适用于gcc
和clang
。我使用它来使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