拒绝指针的数组大小的宏

通常讲授的标准数组大小宏是


#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))

或某些等效形式。但是,当传入一个指针时,这种事情会悄无声息地成功,并且给出的结果在运行时看起来似乎是合理的,直到事情神秘地消失。


犯这样的错误太容易了:重构具有局部数组变量的函数,将数组操作的一部分移到以数组为参数的新函数中。


因此,问题是:是否存在“卫生的”宏来检测ARRAYSIZEC中宏的滥用,最好是在编译时?在C ++中,我们将仅使用专门用于数组参数的模板。在C语言中,似乎我们需要某种方式来区分数组和指针。(例如,如果我想拒绝数组,我会做例如(arr=arr, ...)因为数组分配是非法的)。


RISEBY
浏览 435回答 3
3回答

ITMISS

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需要整数常量表达式。

PIPIONE

此版本的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){&nbsp; &nbsp; int a[5];&nbsp; &nbsp; int *b = a;&nbsp; &nbsp; int n = 10;&nbsp; &nbsp; int c[n]; /* a VLA */&nbsp; &nbsp; printf("%zu\n", ARRAYSIZE(a));&nbsp; &nbsp; printf("%zu\n", ARRAYSIZE(b));&nbsp; &nbsp; printf("%zu\n", ARRAYSIZE(c));&nbsp; &nbsp; return 0;}输出:5010正如本杰克逊(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必须在运行时比较的地址)
打开App,查看更多内容
随时随地看视频慕课网APP