F
Frederick Gotham
Many people use a method quite akin to the following to determine an
array's length:
#define NUMELEM(arr) (sizeof (arr) / sizeof *(arr))
I recall reading an article written by Alf P. Steinbach which listed
several methods of determining an array's length. He listed the pro's and
con's of each.
One of the con's of the above method is that the macro can't detect whether
it is erronously supplied with a pointer instead of an array. (It also
evaluates "arr" twice, which is bad if we call a function which returns an
array by reference!).
In an attempt to overcome the former shortcoming, I've cooked up the
following. It's not a finished product, but you get the idea:
#define NUMELEM(arr) (sizeof (arr) / sizeof *(arr))
template <int positive_or_negative>
struct VerifyType {
unsigned must_not_be_negative : positive_or_negative;
/* Can't have negative bit field */
};
#define VERIFY(compile_time_constant) \
( sizeof(VerifyType< \
(compile_time_constant) ? 1 : -1 \
#define ARRLEN(arr) ((void)VERIFY(NUMELEM(arr) > 1), NUMELEM(arr))
#include <iostream>
using std::cout;
int main()
{
int array[5];
int *p = array;
cout << ARRLEN(array) << '\n';
cout << ARRLEN(p) << '\n'; /* Compiler ERROR */
}
In essence, it simply performs a compile-time assert to ensure that NUMELEM
(arr) is greater than one. Of course, we'll have technicalities such as
arrays whose length is 1.
array's length:
#define NUMELEM(arr) (sizeof (arr) / sizeof *(arr))
I recall reading an article written by Alf P. Steinbach which listed
several methods of determining an array's length. He listed the pro's and
con's of each.
One of the con's of the above method is that the macro can't detect whether
it is erronously supplied with a pointer instead of an array. (It also
evaluates "arr" twice, which is bad if we call a function which returns an
array by reference!).
In an attempt to overcome the former shortcoming, I've cooked up the
following. It's not a finished product, but you get the idea:
#define NUMELEM(arr) (sizeof (arr) / sizeof *(arr))
template <int positive_or_negative>
struct VerifyType {
unsigned must_not_be_negative : positive_or_negative;
/* Can't have negative bit field */
};
#define VERIFY(compile_time_constant) \
( sizeof(VerifyType< \
(compile_time_constant) ? 1 : -1 \
>) )
#define ARRLEN(arr) ((void)VERIFY(NUMELEM(arr) > 1), NUMELEM(arr))
#include <iostream>
using std::cout;
int main()
{
int array[5];
int *p = array;
cout << ARRLEN(array) << '\n';
cout << ARRLEN(p) << '\n'; /* Compiler ERROR */
}
In essence, it simply performs a compile-time assert to ensure that NUMELEM
(arr) is greater than one. Of course, we'll have technicalities such as
arrays whose length is 1.