数组大小 C++宏:它是如何工作的?
好吧,我不完全是新手,但我不能说我理解下面的宏。最令人困惑的部分是将值转换为 size_t 的除法:这到底能实现什么?特别是,因为我看到一个否定运算符,据我所知,它可能会导致零值。这是否意味着它会导致除零错误? (顺便说一句,宏是正确的并且工作得很好。)
#define ARRAYSIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
OK, I'm not entirely a newbie, but I cannot say I understand the following macro. The most confusing part is the division with value cast to size_t: what on earth does that accomplish? Especially, since I see a negation operator, which, as far as I know, might result in a zero value. Does not this mean that it can lead to a division-by-zero error? (By the way, the macro is correct and works beautifully.)
#define ARRAYSIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
最后的除法似乎是尝试检测非数组参数(例如指针)。
例如,它无法检测到
char*
,但可以检测到T*
,其中sizeof(T)
大于大小的一个指针。在C++中,通常更喜欢以下函数模板:
该函数模板不能用指针参数实例化,只能用数组实例化。在 C++11 中,它也可以用
std::begin
和std::end
来表达,这会自动让它适用于具有随机访问迭代器的标准容器。限制:不适用于 C++03 中的本地类型数组,并且不会产生编译时间大小。
对于编译时间大小,您可以像免责声明一样执行
:所有代码均未经过编译器的处理。
但一般来说,只需使用第一个函数模板,
countOf
。干杯&嗯。
The division at the end seems to be an attempt at detecting a non-array argument (e.g. pointer).
It fails to detect that for, for example,
char*
, but would work forT*
wheresizeof(T)
is greater than the size of a pointer.In C++, one usually prefers the following function template:
This function template can't be instantiated with pointer argument, only array. In C++11 it can alternatively be expressed in terms of
std::begin
andstd::end
, which automagically lets it work also for standard containers with random access iterators.Limitations: doesn't work for array of local type in C++03, and doesn't yield compile time size.
For compile time size you can instead do like
Disclaimer: all code untouched by compiler's hands.
But in general, just use the first function template,
countOf
.Cheers & hth.
假设我们有
ARRAYSIZE(arr)
将扩展为(大致),在这种情况下给出 42/!0 即 42
如果由于某种原因 sizeof 数组不能被 sizeof 其元素整除,则除以零将发生。什么时候可以发生?例如,当您传递动态分配的数组而不是静态数组时!
suppose we have
ARRAYSIZE(arr)
will expand to (rougly)which in this case gives 42/!0 which is 42
If for some reason sizeof array is not divisible by sizeof its element, division by zero will occur. When can it happen? For example when you pass a dynamically allocated array instead of a static one!
它确实会导致除零错误(故意)。该宏的工作方式是将数组的大小(以字节为单位)除以单个数组元素的大小(以字节为单位)。因此,如果您有一个
int
值数组,其中int
为 4 个字节(在大多数 32 位机器上),则一个包含 4 个int
的数组> 值将为 16 字节。因此,当您在这样的数组上调用此宏时,它会执行
sizeof(array) / sizeof(*array)
操作。由于 16 / 4 = 4,它返回数组中有 4 个元素。注意:
*array
取消引用数组的第一个元素,相当于array[0]
。第二次除法进行模除(获取除法的余数),并且由于任何非零值都被视为“true”,因此使用
!
运算符将导致除以零,如果除法非零(同样,否则除以 1)。It does lead to a division-by-zero error (intentionally). The way that this macro works is it divides the size of the array in bytes by the size of a single array element in bytes. So if you have an array of
int
values, where anint
is 4 bytes (on most 32-bit machines), an array of 4int
values would be 16 bytes.So when you call this macro on such an array, it does
sizeof(array) / sizeof(*array)
. And since 16 / 4 = 4, it returns that there are 4 elements in the array.Note:
*array
dereferences the first element of the array and is equivalent toarray[0]
.The second division does modulo-division (gets the remainder of the division), and since any non-zero value is considered "true", using the
!
operator would cause a division by zero if the remainder of the division is non-zero (and similarly, division by 1 otherwise).除零可能会尝试捕获由任何原因引起的对齐错误。就像在某些编译器设置下,数组元素的大小为 3,但编译器会将其四舍五入为 4 以加快数组访问速度,那么包含 4 个条目的数组的大小将为 16,并且 !(16/3) 将变为为零,在编译时除以零。然而,我不知道有任何编译器这样做,并且 sizeof 返回与数组中该类型的大小不同的大小可能违反 C++ 规范。
The div-by-zero may be trying to catch alignment errors caused by whatever reason. Like if, with some compiler settings, the size of an array element were 3 but the compiler would round it to 4 for faster array access, then an array of 4 entries would have the size of 16 and !(16/3) would go to zero, giving division-by-zero at compile time. Yet, I don't know of any compiler doing like that, and it may be against the specification of C++ for sizeof to return a size that differs from the size of that type in an array..
来晚了……
谷歌的 C++ 代码库有恕我直言 的
arraysize()
宏的最终 C++ 实现,其中包括一些此处未考虑的问题。我无法改进 来源,注释清晰完整。
Coming late to the party here...
Google's C++ codebase has IMHO the definitive C++ implementation of the
arraysize()
macro, which includes several wrinkles that aren't considered here.I cannot improve upon the source, which has clear and complete comments.
第一部分
(sizeof(a) / sizeof(*(a)))
相当简单;它将整个数组的大小(假设您向宏传递数组类型的对象,而不是指针)除以第一个元素的大小。这给出了数组中元素的数量。第二部分就不那么简单了。我认为潜在的被零除是故意的;如果出于某种原因,数组的大小不是其元素之一的整数倍,则会导致编译时错误。换句话说,这是某种编译时健全性检查。
但是,我不知道在什么情况下会发生这种情况...正如人们在下面的评论中所建议的那样,它会捕获一些误用(例如在一个指针)。但它不会捕获所有这样的错误。
The first part
(sizeof(a) / sizeof(*(a)))
is fairly straightforward; it's dividing the size of the entire array (assuming you pass the macro an object of array type, and not a pointer), by the size of the first element. This gives the number of elements in the array.The second part is not so straightforward. I think the potential division-by-zero is intentional; it will lead to a compile-time error if, for whatever reason, the size of the array is not an integer multiple of one of its elements. In other words, it's some kind of compile-time sanity check.
However, I can't see under what circumstances this could occur... As people have suggested in comments below, it will catch some misuse (like using
ARRAYSIZE()
on a pointer). It won't catch all errors like this, though.我写了这个宏的这个版本。考虑旧版本:
在 64 位计算机上,此代码会生成以下输出:
发生了什么? ARRAYSIZE 是如何从 32 变为 0 的?问题是函数参数实际上是一个指针,尽管它看起来像一个数组。所以在 foo 内部,“sizeof(stats)”是 8 个字节,“sizeof(*stats)”仍然是 144。
使用新宏:
当 sizeof(a) 不是 sizeof(* (a)) 的倍数时, % 不为零,其中 !反转,然后 static_cast 的计算结果为零,导致编译时除以零。因此,在宏中可能的范围内,这种奇怪的除法在编译时捕获了问题。
PS:在C++17中,只需使用std::size,参见http://en .cppreference.com/w/cpp/iterator/size
I wrote this version of this macro. Consider the older version:
On a 64-bit machine, this code produces this output:
What's going on? How did the ARRAYSIZE go from 32 to zero? Well, the problem is the function parameter is actually a pointer, even though it looks like an array. So inside of foo, "sizeof(stats)" is 8 bytes, and "sizeof(*stats)" is still 144.
With the new macro:
When sizeof(a) is not a multiple of sizeof(* (a)), the % is not zero, which the ! inverts, and then the static_cast evaluates to zero, causing a compile-time division by zero. So to the extent possible in a macro, this weird division catches the problem at compile-time.
PS: in C++17, just use std::size, see http://en.cppreference.com/w/cpp/iterator/size