Autre façon de calculer la taille d’un type en utilisant l’arithmétique de pointeur

Le code suivant est-il 100% portable?

int a=10; size_t size_of_int = (char *)(&a+1)-(char*)(&a); // No problem here? std::cout<<size_of_int;// or printf("%zu",size_of_int); 

PS : La question est uniquement à des fins d’apprentissage. Donc, s’il vous plaît, ne donnez pas de réponses telles que Use sizeof() etc.

De ANSI-ISO-IEC 14882-2003, p.87 (c ++ 03):

“75) Une autre façon d’approcher l’arithmétique de pointeur consiste d’abord à convertir le (s) pointeur (s) en pointeur (s) à caractère (s): l’object initialement pointé et le pointeur résultant est reconverti en type d’origine. Pour la soustraction de pointeur, le résultat de la différence entre les pointeurs de caractère est également divisé par la taille de l’object pointé à l’origine. ”

Cela semble suggérer que la différence de pointeur est égale à la taille de l’object.

Si nous enlevons l’UB’ness d’incrémenter un pointeur sur un scalaire a et transformons un en tableau:

 int a[1]; size_t size_of_int = (char*)(a+1) - (char*)(a); std::cout< 

Alors cela semble OK. Les clauses relatives aux exigences d'alignement sont cohérentes avec la note de bas de page, si les exigences d'alignement sont toujours divisibles par la taille de l'object.

MISE À JOUR: Intéressant. Comme la plupart d'entre vous le savent probablement, GCC permet de spécifier un alignement explicite sur les types en tant qu'extension. Mais je ne peux pas casser la méthode "sizeof" d'OP avec elle parce que GCC refuse de la comstackr:

 #include  typedef int a8_int __atsortingbute__((aligned(8))); int main() { a8_int v[2]; printf("=>%d\n",((char*)&v[1]-(char*)&v[0])); } 

Le message est error: alignment of array elements is greater than element size .

&a+1 conduira à un comportement indéfini selon la norme C ++ 5.7 / 5:

Lorsqu’une expression de type intégral est ajoutée ou soustraite à un pointeur, le résultat a le type de l’opérande de pointeur. <...> Si l’opérande de pointeur et le résultat pointent tous deux sur des éléments du même object tableau ou sur l’un des éléments passés après le dernier élément de l’object tableau, l’évaluation ne doit pas produire de dépassement de capacité; sinon, le comportement n’est pas défini .

&a+1 est correct selon 5.7 / 4:

Pour les besoins de ces opérateurs, un pointeur sur un object non-array se comporte de la même façon qu’un pointeur sur le premier élément d’un tableau de longueur un avec le type de l’object comme type d’élément.

Cela signifie que 5.7 / 5 peut être appliqué sans UB. Et enfin, la remarque 75 de 5.7 / 6 telle que @Luther Blissett noté dans sa réponse que le code de la question est valide.


Dans le code de production, utilisez plutôt sizeof . Mais le standard C ++ ne garantit pas que sizeof(int) donnera 4 sur toutes les plates-formes 32 bits.

Non, ce code ne fonctionnera pas comme prévu sur chaque plate-forme. Au moins en théorie, il pourrait y avoir une plate-forme avec par exemple des entiers de 24 bits (= 3 octets) mais un alignement de 32 bits. De tels alignements ne sont pas inhabituels pour les plates-formes (plus anciennes ou plus simples). Ensuite, votre code renverrait 4, mais sizeof (int) renverrait 3.

Mais je ne suis pas au courant d’un matériel réel qui se comporte de cette façon. En pratique, votre code fonctionnera sur la plupart ou la totalité des plates-formes.

Ce n’est pas 100% portable pour les raisons suivantes:

  1. Edit: Vous feriez mieux d’utiliser int a[1]; et alors a+1 devient définitivement valide.
  2. & a invoque un comportement indéfini sur les objects de la classe de stockage de registre.
  3. En cas de ressortingctions d’alignement supérieures ou égales à la taille de type int , size_of_int ne contiendra pas la réponse correcte.

Avertissement:

Je ne suis pas sûr si ce qui précède est valable pour C ++.

Pourquoi pas simplement:

 size_t size_of_int = sizeof(int); 

C’est probablement la mise en œuvre définie.

Je peux imaginer un système (hypothétique) où sizeof (int) est plus petit que l’alignement par défaut.

Il semble prudent de dire que size_of_int >= sizeof(int)

Le code ci-dessus calculera de manière portable sizeof(int) sur une plate-forme cible, mais cette dernière est définie par l’implémentation. Vous obtiendrez des résultats différents sur des plates-formes différentes.

Oui, cela vous donne l’équivalent de sizeof(a) mais en utilisant ptrdiff_t au lieu de type size_t .

Il y a eu un débat sur une question similaire .

Voir les commentaires sur ma réponse à cette question pour quelques indications sur la raison pour laquelle ceci est non seulement non portable, mais aussi un comportement non défini par la norme.