Reputation: 2729
Here is a macro for getting array size
#define array_size(array) \
(sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*)))
I think normally (sizeof( array ) / (sizeof( array[0] )) is good enough to get the size of the array.
I guess the part
(sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))
is to avoid the whole thing divided by zero, anyone could help to explain?
Thanks in advance.
Cheers,
Upvotes: 8
Views: 494
Reputation: 13451
I think normally (sizeof( array ) / (sizeof( array[0] )) is good enough to get the size of the array.
Although it is not your primary question, but you mentioned it. The correct way to determine array size in C++ is using templates:
template<typename T, size_t size>
constexpr size_t array_size(T(&)[size]){
return size;
}
Upvotes: 6
Reputation: 16726
I assume this part is clear: sizeof( array ) / sizeof( array[0] )
This part (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))
is a logical expression, so yielding true or false. When computing the whole expression, so multiplying sizeof( array[0] )
with the logical expression, the compiler converts the logical expression to 0 or 1. So you end up with
sizeof( array ) / (sizeof( array[0] ) * 1)
or
sizeof( array ) / (sizeof( array[0] ) * 0)
.
The first case is the normal and desired case. The second case will give you a compiler error because of division by zero. So the code will not compile if you call for example:
long *p; // assuming a platform with sizeof(long)==sizeof(void*)
array_size(p);
But it will not catch errors like:
char *p;
array_size(p);
And it will fail to compile for a case I'ld want it to compile for:
long x[1]; // assuming a platform with sizeof(long)==sizeof(void*)
array_size(x);
BTW, if you are declaring this function as a macro (and in C++ I'ld really prefer the template style solution), you should change all array
in the macro to (array)
.
Upvotes: 1
Reputation: 183858
Multiplying sizeof array[0]
in the divisor by
(sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))
makes the divisor zero if
sizeof array == sizeof(void*)
and
sizeof array[0] > sizeof(void*)
In those cases, you get a division by zero during the compilation, which would cause the compilation to fail.
These checks are an attempt to detect arguments that are pointers (be they the result of array-to-pointer conversion or not), since one can't know how large an "array" a pointer points to by using that quotient.
It fails if other pointer types have different sizes than void*
, and it doesn't detect pointers to things that are not larger than void*
s. It probably does more harm than good by lulling the author in a false sense of security.
Upvotes: 12