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