Macro ARRAYSIZE C ++: comment ça marche?
OK, je ne suis pas entièrement un débutant, mais je ne peux pas dire que je comprends la macro suivante. La partie la plus déroutante est la division de la valeur de fonte à size_t: ce qui sur terre n'est que d'accomplir? Surtout, depuis que je vois un opérateur de négation, qui, autant que je sache, pourrait entraîner une valeur de zéro. Ne ce à dire qu'il peut conduire à une division par zéro? (En passant, la macro est correct et fonctionne à merveille.)
#define ARRAYSIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
source d'informationauteur Lajos Nagy
Vous devez vous connecter pour publier un commentaire.
La première partie
(sizeof(a) /sizeof(*(a)))
est assez simple; c'est la division de la taille de l'ensemble de la matrice (en supposant que vous passez la macro à un objet de type tableau, et non pas un pointeur), par la taille du premier élément. Cela donne le nombre d'éléments dans le tableau.La deuxième partie n'est pas si simple. Je pense que le potentiel de division par zéro est intentionnelle; elle conduira à une erreur de compilation si, pour quelque raison que ce soit, la taille du tableau n'est pas un multiple entier de l'un de ses éléments. En d'autres termes, c'est une sorte de au moment de la compilation sanity check.
Cependant, je ne vois pas dans quelles circonstances cela pourrait se produire... Comme les gens l'ont suggéré dans les commentaires ci-dessous, il va attraper certains abus (comme l'utilisation de
ARRAYSIZE()
sur un pointeur). Il ne sera pas rattraper toutes les erreurs de ce type, cependant.La division à la fin semble être un tentative à la détection d'une non-argument de tableau (par exemple, le pointeur).
Il ne parvient pas à détecter que pour, par exemple,
char*
mais travaillent pour laT*
oùsizeof(T)
est plus grande que la taille d'un pointeur.En C++, en général on préfère le suivant modèle de fonction:
Ce modèle de fonction ne peut pas être instanciée avec le pointeur argument, seulement de tableau. En C++11, il peut également être exprimée en termes de
std::begin
etstd::end
qui automagiquement permet de travailler aussi pour les conteneurs standard avec des itérateurs à accès aléatoire.Limitations: ne fonctionne pas pour tableau de type local en C++03, et ne donne pas de temps de compilation de taille.
Pour la compilation de la taille de la place, vous pouvez faire comme
Avertissement: tous les code épargnée par le compilateur.
Mais en général, il suffit d'utiliser la fonction première de modèle,
countOf
.Cheers & hth.
supposons que nous avons
ARRAYSIZE(arr)
sera étendue à d' (trajet en voiture)qui dans ce cas donne 42/!0 qui est 42
Si pour une raison quelconque sizeof tableau n'est pas divisible par sizeof son élément, la division par zéro se produit. Quand peut-il arriver? Par exemple, lorsque vous passez un tableau alloué dynamiquement au lieu de statique!
Ça conduit à une division par zéro (intentionnellement). La façon dont cette macro fonctionne est-il divise la taille du tableau, en octets, de la taille d'un élément de tableau unique en octets. Donc, si vous avez un tableau de
int
valeurs, où unint
est de 4 octets (sur la plupart des machines 32 bits), un tableau de 4int
de valeurs de 16 octets.Ainsi, lorsque vous appelez cette macro sur un tel tableau, il ne
sizeof(array) /sizeof(*array)
. Et depuis le 16 /4 = 4, il revient qu'il y a 4 éléments dans le tableau.Remarque:
*array
déréférence le premier élément du tableau et est équivalent àarray[0]
.La deuxième division ne modulo-division (obtient le reste de la division), et depuis toute valeur non nulle est considérée comme "vraie", à l'aide de la
!
opérateur serait la cause d'une division par zéro si le reste de la division est non nulle (et, de même, la division par 1 dans le cas contraire).J'ai écrit cette version de cette macro. Envisager l'ancienne version:
Sur une machine 64 bits, ce code génère cette sortie:
Ce qu'il se passe? Comment le ARRAYSIZE aller de 32 à zéro? Eh bien, le problème est le paramètre de la fonction est en fait un pointeur, même s'il ressemble à un tableau. Donc, à l'intérieur de foo, "sizeof(stats)" est de 8 octets, et "sizeof(*statistiques)" est encore 144.
Avec la nouvelle macro:
Quand sizeof(a) n'est pas un multiple de sizeof(* (a)), le % n'est pas à zéro, ce qui le ! inverse, puis le static_cast évalue à zéro, à l'origine au moment de la compilation de la division par zéro. Donc, dans la mesure du possible dans une macro, cette étrange division attrape le problème à la compilation.
PS: en C++17, il suffit d'utiliser std::taille, voir http://en.cppreference.com/w/cpp/iterator/size
La division par zéro peut être en essayant d'attraper les erreurs d'alignement causée par quelque raison que ce soit. Comme si, avec certains paramètres du compilateur, de la taille d'un élément du tableau 3, mais le compilateur aurait arrondir à 4 pour les plus rapides d'accès au tableau, puis un tableau de 4 entrées ont la taille de 16 et !(16/3) irait à zéro, en donnant la division par zéro au moment de la compilation. Pourtant, je ne sais pas du tout compilateur de faire comme ça, et c'est peut être par rapport à la spécification de C++ pour sizeof pour revenir à une taille différente de la taille de ce type dans un tableau..
Arrivé en retard à la fête ici...
De Google, C++, base de code a mon humble avis la définitive C++ mise en œuvre de la
arraysize()
macro, qui comprend plusieurs rides qui ne sont pas considérés ici.Je ne peux pas améliorer la sourcequi a une vision claire et complète des commentaires.