本文介绍了拒绝指针的数组大小的宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

经常教的标准数组大小的宏是

The standard array-size macro that is often taught is

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

或某种等效的形式.然而,当传入一个指针时,这种事情会悄悄地成功,并给出在运行时看似合理的结果,直到事情神秘地崩溃.

or some equivalent formation. However, this kind of thing silently succeeds when a pointer is passed in, and gives results that can seem plausible at runtime until things mysteriously fall apart.

犯这个错误太容易了:一个具有局部数组变量的函数被重构,将一些数组操作移到一个以数组作为参数调用的新函数中.

It's all-too-easy to make this mistake: a function that has a local array variable is refactored, moving a bit of array manipulation into a new function called with the array as a parameter.

那么,问题是:是否有一个卫生"宏来检测 C 中 ARRAYSIZE 宏的滥用,最好是在编译时?在 C++ 中,我们只使用专门用于数组参数的模板;在 C 中,似乎我们需要某种方法来区分数组和指针.(例如,如果我想拒绝数组,我只会做例如 (arr=arr, ...) 因为数组分配是非法的).

So, the question is: is there a "sanitary" macro to detect misuse of the ARRAYSIZE macro in C, preferably at compile-time? In C++ we'd just use a template specialized for array arguments only; in C, it seems we'll need some way to distinguish arrays and pointers. (If I wanted to reject arrays, for instance, I'd just do e.g. (arr=arr, ...) because array assignment is illegal).

推荐答案

Linux 内核使用了一个很好的 ARRAY_SIZE 实现来处理这个问题:

Linux kernel uses a nice implementation of ARRAY_SIZE to deal with this issue:

#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 中有效.

Of course this is portable only in GNU C as it makes use of two instrinsics: typeof operator and __builtin_types_compatible_p function. Also it uses their "famous" BUILD_BUG_ON_ZERO macro which is only valid in GNU C.

假设有一个编译时评估要求(这是我们想要的),我不知道这个宏的任何可移植实现.

Assuming a compile time evaluation requirement (which is what we want), I don't know any portable implementation of this macro.

半便携式"实现(并不会涵盖所有情况)是:

A "semi-portable" implementation (and which would not cover all cases) is:

#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_ARRAY 表达式不是整数常量表达式(整数常量表达式中不允许转换为指针类型和下标运算符)并且 STATIC_EXP 中的位域宽度需要一个整数常量表达式.

With gcc this gives no warning if argument is an array in -std=c99 -Wall but -pedantic would gives a warning. The reason is IS_ARRAY expression is not an integer constant expression (cast to pointer types and subscript operator are not allowed in integer constant expressions) and the bit-field width in STATIC_EXP requires an integer constant expression.

这篇关于拒绝指针的数组大小的宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 08:33