3 回答
TA贡献1871条经验 获得超8个赞
Linux内核使用了一个不错的实现ARRAY_SIZE来解决此问题:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
与
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
和
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
当然,这仅在GNU C中是可移植的,因为它使用了两个内在原理: typeof运算符和__builtin_types_compatible_p函数。它还使用BUILD_BUG_ON_ZERO仅在GNU C中有效的“著名” 宏。
假设有一个编译时评估要求(这就是我们想要的),我不知道该宏的任何可移植实现。
“半便携式”实现(并且不能涵盖所有情况)是:
#define ARRAY_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) + STATIC_EXP(IS_ARRAY(arr)))
与
#define IS_ARRAY(arr) ((void*)&(arr) == &(arr)[0])
#define STATIC_EXP(e) \
(0 * sizeof (struct { int ARRAY_SIZE_FAILED:(2 * (e) - 1);}))
随着gcc如果参数是一个数组这个没有给出警告,-std=c99 -Wall但-pedantic会发出警告。原因是IS_ARRAYexpression不是整数常量表达式(整数常量表达式中不允许转换为指针类型和下标运算符),并且in的位字段宽度STATIC_EXP需要整数常量表达式。
TA贡献1829条经验 获得超9个赞
此版本的ARRAYSIZE()return 0when arr是指针,而其大小是纯数组时的大小
#include <stdio.h>
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
#define ARRAYSIZE(arr) (IS_ARRAY(arr) ? (sizeof(arr) / sizeof(arr[0])) : 0)
int main(void)
{
int a[5];
int *b = a;
int n = 10;
int c[n]; /* a VLA */
printf("%zu\n", ARRAYSIZE(a));
printf("%zu\n", ARRAYSIZE(b));
printf("%zu\n", ARRAYSIZE(c));
return 0;
}
输出:
5
0
10
正如本杰克逊(Ben Jackson)指出的那样,您可以强制运行时异常(除以0)
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
#define ARRAYSIZE(arr) (sizeof(arr) / (IS_ARRAY(arr) ? sizeof(arr[0]) : 0))
可悲的是,您不能强制执行编译时错误(arg必须在运行时比较的地址)
- 3 回答
- 0 关注
- 469 浏览
添加回答
举报