Nota despre cod: ce misto era daca forumul nu taia codul dintre mai mic mai mare. Pina se rezolva cu paranoia am pus $ unde urmau sa vina caracterele respective.
Presupun ca mai toata lumea stie cum se determina cite elemente are un array pre-alocat:
Cod sursã:
#include $stdio.h$
struct Ceva
{
int x;
char y[19];
short z;
};
Ceva g_theArray[42];
#define NUM_ELEMS(a) ((sizeof(a) / sizeof(a[0]))
int main()
{
int numElems = NUM_ELEMS(g_theArray); // returneaza 42
printf("%dn", numElems);
}
Toate bune si frumoase pe vremea lui C, dar exista o problema:
Cod sursã:
Ceva* altArray = new Ceva[42];
int numElems1 = NUM_ELEMS(altArray); // Returneaza 0.
int* arrayDeInt = new int[42];
int numElems2 = NUM_ELEMS(arrayDeInt); // In general returneaza 1 sau 2.
Problema aici e ca sizeof() ne da dimensiunea pointerului, ca n-are de unde sa stie dimensiunea array-ului alocat dinamic. Un pointer are 4 sau 8 bytes pe majoritatea platformelor, insa Ceva e mai mare, asa ca atunci cind le impartim ca intregi ne da 0.
Nu se poate obtine marimea unui array alocat dinamic (in C++ chior, ca daca ne apucam sa facem chestii platform-specific se poate). Se poate insa sa evitam folosirea gresita a lui NUM_ELEMS, adica sa dea eroare de compilare cind argumentul e un pointer, nu un array alocat static. Header-ul stdlib.h din CRT-ul de la VS 2005 are un macro _countof definit (aproape) in felul urmator:
Cod sursã:
#if !defined(__cplusplus)
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
extern "C++"
{
template $ typename _CountofType, size_t _SizeOfArray $
char (*__countof_helper(_CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*__countof_helper(_Array))
}
#endif
In C, face aia cu impartirea si gata. In C++ insa, face o smecherie cu template-uri astfel incit:
Cod sursã:
int a[19];
int b* = new b[20];
int x = _countof(a); // 20
int y = _countof(b); // compiler error
Codul nu foloseste nici o extensie de VC, deci merge in orice compilator intreg la cap. Evident, daca va decideti sa-l bagati in codul propriu trebuie sa redenumiti __countof_helper, _CountofType, _SizeOfArray, _Array si _countof pentru ca toti sint identificatori rezervati (incep cu underscore). Eu l-am bagat la mine in felul urmator:
Cod sursã:
template $ typename Type, size_t SizeOfArray $
char (*StaticArrayNumElemsHelper(Type (&arr)[SizeOfArray]))[SizeOfArray];
#define STATIC_ARRAY_NUM_ELEMS(x) sizeof(*StaticArrayNumElemsHelper(x))
Bonus points pentru cine se prinde de ce functioneaza. Hint: sintaxa pentru declarat array-uri nu-i intotdeauna ceea ce pare a fi.

PS: definitia originala are si un calificator UNALIGNED pe-acolo, il gasiti si singuri cu go to definition la _countof. In VC, macro-ul UNALIGNED se expandeaza in nimic pe 32 de biti, iar pe 64 de biti se expandeaza in keyword-ul __unaligned. Nu pricep de ce e nevoie de el, am testat si merge si fara pe 64 de biti.