Macro definition ARRAY_SIZE
Macro definition ARRAY_SIZE
我在Google V8项目中读取global .h时遇到了以下宏定义:
// The expression ARRAY_SIZE(a) is a compile-time constant of type
// size_t which represents the number of elements of the given
// array. You should only use ARRAY_SIZE on statically allocated
// arrays.
#define ARRAY_SIZE(a)
((sizeof(a) / sizeof(*(a))) /
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
我的问题是后一部分:static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
。我的一个想法是:由于后一部分总是求值为1
,而size_t
类型,因此整个表达式将提升为size_t
。
如果这个假设是正确的,那么就会出现另一个问题:既然sizeof
操作符的返回类型是size_t,为什么需要这样的提升?以这种方式定义宏的好处是什么?
如前所述,这是一个微弱的(*)尝试,以确保宏不会与指针(而不是真数组)一起使用,因为它不会正确评估数组的大小。这当然源于这样一个事实:宏是纯基于文本的操作,没有AST的概念。
由于这个问题也被标记为c++,我想指出c++提供了一个类型安全的替代方案:模板。
#ifdef __cplusplus
template <size_t N> struct ArraySizeHelper { char _[N]; };
template <typename T, size_t N>
ArraySizeHelper<N> makeArraySizeHelper(T(&)[N]);
# define ARRAY_SIZE(a) sizeof(makeArraySizeHelper(a))
#else
# // C definition as shown in Google's code
#endif
或者,很快就可以使用constexpr
:
template <typename T, size_t N>
constexpr size_t size(T (&)[N]) { return N; }
然而,我最喜欢的编译器(Clang)仍然没有实现它们:x
在这两种情况下,由于函数不接受指针形参,如果类型不正确,则会得到编译时错误。
(*)很弱,因为它不适用于对象大小为指针大小的除数的小对象。
只是为了证明它是一个编译时值:
template <size_t N> void print() { std::cout << N << "n"; }
int main() {
int a[5];
print<ARRAY_SIZE(a)>();
}
在IDEONE上看
后一部分的计算结果总是1,类型为size_t,
理想情况下,后面的部分将评估为bool
(即true
/false
),并使用static_cast<>
,它被转换为size_t
。
为什么这样的推广是必要的?定义一个的好处是什么以这种方式进行宏观调控?
我不知道这是否是定义宏的理想方式。然而,我在评论中找到了一个灵感://You should only use ARRAY_SIZE on statically allocated arrays.
假设,如果有人传递一个指针,那么struct
(如果它大于指针大小)数据类型将失败。
struct S { int i,j,k,l };
S *p = new S[10];
ARRAY_SIZE(p); // compile time failure !
[注:此技术可能不会显示int*
, char*
的任何错误]
如果sizeof(a) / sizeof(*a)
有余数(即a
不是*a
的整数),则表达式将求值为0
,编译器将在编译时给您一个除零错误。
我只能假设这个宏的作者在过去被一些没有通过测试的东西烧毁了
在Linux内核中,宏被定义为(特定于GCC):
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
其中__must_be_array()
为
/* &a[0] degrades to a pointer: a different type from an array */
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
和__same_type()
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
第二部分要确保sizeof( a )
能被sizeof( *a )
整除。
因此(sizeof(a) % sizeof(*(a)))
部分。如果它是可整除的,表达式将被求值为0
。下面是!
部分- !(0)
将给出true
。这就是为什么需要演员的原因。实际上,这并不影响大小的计算,只是增加了编译时检查。
由于是在编译时,如果(sizeof(a) % sizeof(*(a)))
不是0
,那么0除法就会出现编译时错误。
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 大于65535的C++数组[size]引发不一致的溢出
- 为什么(-1)%vector::size()总是返回0
- 从 std::string 到 std::array<char,size> 的 memcopy 额外数据是否是一种未定义的行为?
- 为什么我必须在初始化 std::array<SomeStruct, size> 时指定每个项目的类型C++
- 如何在 JniWrapper 中将 Java ArrayList<float[]> 映射到C++ Vector<array<float,size>>?
- 使用 constexpr 作为 std::array size
- 警告的原因是什么:"when type is in parentheses, array cannot have dynamic size"?
- std::span.size() vs array/vector size
- std::array::max_size 和 std::array::size 给出不同结果的示例
- 为什么 std::array::size 不是静态的?
- 具有恒定大小数组的警告"ISO C++ forbids variable-size array"
- 为什么 std::array::size constexpr 具有简单类型(int、double、..),而不是 std
- 如何在 c++11 中使用容器 std::array<type, size> 用于多维数组?
- 使用 std::array::size 实例化 std::array 时出错
- 为什么我会得到"cannot allocate an array of constant size 0"?
- 在比较 array.size() 与负值时获得 if 条件的意外行为
- ARRAY[T, SIZE]合适的默认构造函数可用
- c++中的快速排序array.size()错误
- 从(bad) array[size]移动到array = new float[size]