ARRAYSIZE C++ 宏:它是如何工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4064134/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:27:07  来源:igfitidea点击:

ARRAYSIZE C++ macro: how does it work?

c++c-preprocessor

提问by Lajos Nagy

OK, I'm not entirelya 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 iscorrect and works beautifully.)

好吧,我不完全是新手,但我不能说我理解以下宏。最令人困惑的部分是将值转换为 size_t 的除法:这到底完成了什么?特别是,因为我看到了一个否定运算符,据我所知,它可能会导致零值。这是否意味着它会导致除以零错误?(顺便说一下,宏正确的,而且效果很好。)

#define ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / \
  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

采纳答案by Oliver Charlesworth

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.

第一部分(sizeof(a) / sizeof(*(a)))相当简单;它将整个数组的大小(假设您向宏传递数组类型的对象,而不是指针)除以第一个元素的大小。这给出了数组中的元素数。

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 somemisuse (like using ARRAYSIZE()on a pointer). It won't catch all errors like this, though.

但是,我看不出在什么情况下会发生这种情况......正如人们在下面的评论中所建议的那样,它会引起一些误用(例如ARRAYSIZE()在指针上使用)。但是,它不会捕获所有这样的错误。

回答by Cheers and hth. - Alf

The division at the end seems to be an attemptat detecting a non-array argument (e.g. pointer).

最后的除法似乎是试图检测非数组参数(例如指针)。

It fails to detect that for, for example, char*, but would work for T*where sizeof(T)is greater than the size of a pointer.

例如,它无法检测到char*,但可以用于大于指针大小的T*where sizeof(T)

In C++, one usually prefers the following function template:

在 C++ 中,人们通常更喜欢以下函数模板:

typedef ptrdiff_t Size;

template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }

This function template can't be instantiated with pointer argument, only array. In C++11 it can alternatively be expressed in terms of std::beginand std::end, which automagically lets it work also for standard containers with random access iterators.

这个函数模板不能用指针参数实例化,只能用数组实例化。在 C++11 中,它也可以用std::begin和表示std::end,这自动让它也适用于具有随机访问迭代器的标准容器。

Limitations: doesn't work for array of local type in C++03, and doesn't yield compile time size.

限制:不适用于 C++03 中的本地类型数组,并且不会产生编译时间大小。

For compile time size you can instead do like

对于编译时间大小,您可以改为这样做

template< Size n > struct Sizer { char elems[n]; };

template< class Type, size n >
Sizer<n> countOf_( Type (&)[n] );

#define COUNT_OF( a ) sizeof( countOf_( a ).elems )

Disclaimer: all code untouched by compiler's hands.

免责声明:所有代码都没有经过编译器的手。

But in general, just use the first function template, countOf.

但一般情况下,只需使用第一个函数模板,countOf.

Cheers & hth.

干杯& hth。

回答by Armen Tsirunyan

suppose we have

假设我们有

T arr[42];

ARRAYSIZE(arr)will expand to (rougly)

ARRAYSIZE(arr)将扩展到(粗略地)

sizeof (arr) / sizeof(*arr) / !(sizeof(arr) % sizeof(*arr))

which in this case gives 42/!0 which is 42

在这种情况下,它给出 42/!0 即 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!

如果由于某种原因 sizeof 数组不能被它的元素 sizeof 整除,则会发生被零除。什么时候可以发生?例如,当您传递动态分配的数组而不是静态数组时!

回答by jorgbrown

I wrote this version of this macro. Consider the older version:

我写了这个宏的这个版本。考虑旧版本:

#include <sys/stat.h>
#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))

int main(int argc, char *argv[]) {
  struct stat stats[32];
  std::cout << "sizeof stats = " << (sizeof stats) << "\n";
  std::cout << "sizeof *stats = " << (sizeof *stats) << "\n";
  std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "\n";

  foo(stats);
}

void foo(struct stat stats[32]) {
  std::cout << "sizeof stats = " << (sizeof stats) << "\n";
  std::cout << "sizeof *stats = " << (sizeof *stats) << "\n";
  std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "\n";
}

On a 64-bit machine, this code produces this output:

在 64 位机器上,此代码产生以下输出:

sizeof stats = 4608
sizeof *stats = 144
ARRAYSIZE=32
sizeof stats = 8
sizeof *stats = 144
ARRAYSIZE=0

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.

这是怎么回事?ARRAYSIZE 是如何从 32 变为 0 的?好吧,问题是函数参数实际上是一个指针,即使它看起来像一个数组。所以在 foo 里面,"sizeof(stats)" 是 8 个字节,而 "sizeof(*stats)" 仍然是 144。

With the new macro:

使用新宏:

#define ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / \
  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

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.

当 sizeof(a) 不是 sizeof(* (a)) 的倍数时,% 不为零,即 ! 反转,然后 static_cast 计算为零,导致编译时除以零。因此,在宏中可能的范围内,这种奇怪的划分会在编译时捕获问题。

PS: in C++17, just use std::size, see http://en.cppreference.com/w/cpp/iterator/size

PS:在 C++17 中,只使用 std::size,参见http://en.cppreference.com/w/cpp/iterator/size

回答by Jengerer

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 intvalues, where an intis 4 bytes (on most 32-bit machines), an array of 4 intvalues would be 16 bytes.

它确实会导致被零除错误(故意)。这个宏的工作方式是将数组的大小(以字节为单位)除以单个数组元素的大小(以字节为单位)。因此,如果您有一个int值数组,其中 anint是 4 个字节(在大多数 32 位机器上),一个 4 个int值的数组将是 16 个字节。

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.

所以当你在这样的数组上调用这个宏时,它会sizeof(array) / sizeof(*array)。由于 16 / 4 = 4,它返回数组中有 4 个元素。

Note: *arraydereferences the first element of the array and is equivalent to array[0].

注意:*array取消引用数组的第一个元素,等效于array[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).

第二个除法进行模除(获得除法的余数),并且由于任何非零值都被认为是“真”,!如果除法的余数非零(和类似地,否则除以 1)。

回答by Vesa

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..

div-by-zero 可能试图捕捉由任何原因引起的对齐错误。就像,如果使用某些编译器设置,数组元素的大小为 3,但编译器会将其四舍五入为 4 以加快数组访问,那么包含 4 个条目的数组的大小将为 16 并且 !(16/3) 将变为为零,在编译时给出除以零。然而,我不知道有任何编译器这样做,并且它可能违反 C++ 的规范,因为 sizeof 返回与数组中该类型的大小不同的大小。

回答by Tom Swirly

Coming late to the party here...

来这里参加派对迟到了...

Google's C++ codebase has IMHO thedefinitive C++ implementation of the arraysize()macro, which includes several wrinkles that aren't considered here.

恕我直言Google 的 C++ 代码库是arraysize()最终 C++ 实现,其中包括此处未考虑的几个问题。

I cannot improve upon the source, which has clear and complete comments.

我无法改进来源,它有清晰完整的评论。