Pointeur arithmétique et promotion intégrale

Dans l’expression p + ap est un type de pointeur et a est un entier, les règles de promotion des entiers s’appliqueront-elles? Par exemple, si a est un caractère, sur une machine 64 bits, il sera sûrement étendu à 64 bits avant d’être ajouté à la valeur du pointeur (dans l’assembly compilé), mais est-ce spécifié par les normes? Sur quoi sera-t-il promu? int , intptr_t ou ptrdiff_t ? En quoi les caractères unsigned char ou size_t seront-ils convertis?

Pour qu’une promotion se produise, la norme ne semble pas exiger la présence de char :

Pour les ajouts, les deux opérandes doivent avoir un type d’énumération arithmétique ou non réduite, ou l’un des opérandes doit être un pointeur sur un type d’object complètement défini et l’autre doit être de type énumération intégrée ou non

Il semble que les implémentations dépendent du type d’ajouts de pointeurs permis par l’architecture sous-jacente. Ainsi, si l’architecture prend en charge address+BYTE , tout va bien avec char . Sinon, la promotion sera probablement effectuée à la plus petite taille de décalage d’adresse supscope.

Le résultat de la soustraction des pointeurs est défini comme étant du type `std :: ptrdiff_t ‘

Lorsque deux pointeurs sur des éléments du même object de tableau sont soustraits, le résultat est la différence entre les indices des deux éléments de tableau. Le type du résultat est un type intégral signé signé; ce type doit être le même que celui défini comme std :: ptrdiff_t dans l’en-tête

C ++ 11 §5.7 / 1:

“Les opérateurs additifs + et - groupe de gauche à droite. Les conversions arithmétiques habituelles sont effectuées pour des opérandes de type arithmétique ou énumération. ”

Cela réduit apparemment le problème à la prise en compte des conversions arithmétiques habituelles , définies par…

C ++ 11 §5 / 9:

«De nombreux opérateurs binarys qui attendent des opérandes de type arithmétique ou d’énumération provoquent des conversions et génèrent des types de résultat de la même manière. Le but est de générer un type commun, qui est également le type du résultat. Ce modèle est appelé les conversions arithmétiques usuelles , qui sont définies comme suit:

  • Si l’un des opérandes est du type énumération étendue (7.2), aucune conversion n’est effectuée. si l’autre opérateur n’a pas le même type, l’expression est mal formée.

  • Si l’un des opérandes est de type long double , l’autre sera converti en long double .

  • Sinon, si l’un des opérandes est double , l’autre doit être converti en double .

  • Sinon, si l’un des opérandes est float , l’autre doit être converti en float .

  • Sinon, les promotions intégrales (4.5) doivent être effectuées sur les deux opérandes. Ensuite, les règles suivantes doivent être appliquées aux opérandes promus:

    • Si les deux opérandes ont le même type, aucune conversion supplémentaire n’est nécessaire.

    • Sinon, si les deux opérandes ont des types entiers signés ou des types entiers non signés, l’opérande ayant le type de rang de conversion inférieur doit être converti en un type d’opérande de rang supérieur.

    • Sinon, si l’opérande de type entier non signé a un rang supérieur ou égal au rang du type de l’autre opérande, l’opérande de type entier signé doit être converti en un type d’opérande de type entier non signé.

    • Sinon, si le type de l’opérande avec le type entier signé peut représenter toutes les valeurs du type de l’opérande avec le type entier non signé, l’opérande avec le type entier non signé doit être converti au type de l’opérande avec le type entier signé.

    • Sinon, les deux opérandes doivent être convertis en un type entier non signé correspondant au type d’opérande avec un type entier signé. ”

Suivi mécaniquement, cet ensemble de règles se retrouverait dans la dernière puce (tiret dans la norme) et convertirait un opérande de pointeur au type entier non signé correspondant à un élément non existant. Ce qui est juste faux. Ainsi, le libellé “Les conversions arithmétiques habituelles sont exécutées pour des opérandes de type arithmétique ou énumération” ne peut pas être interprété littéralement – il est IMHO défectueux – mais doit être interprété comme “Les conversions arithmétiques habituelles sont exécutées pour des invocations où les deux opérandes sont d’arithmétique ou d’énumération type”

Ainsi, les promotions en tant que telles, qui sont invoquées via les conversions arithmétiques habituelles, n’entrent en jeu lorsqu’un opérande est un pointeur.

Mais un peu plus loin au §5.7 on trouve…

C ++ 11 §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 pointe sur un élément d’un object tableau et que le tableau est suffisamment grand, le résultat pointe sur un élément décalé par rapport à l’élément d’origine, de sorte que la différence entre les indices des éléments du tableau résultant et original soit égale à l’expression intégrale. ”

Cela définit entièrement le résultat en termes d’indexation de tableaux. Pour un tableau de caractères, la différence d’indices peut dépasser la plage de ptrdiff_t . Un moyen raisonnable pour une implémentation de size_t consiste à convertir l’argument non-pointeur en un type entier non-signé size_t (extension de la signature au niveau du bit) et à utiliser cette valeur avec une arithmétique modulaire pour calculer la valeur de pointeur résultante.

Je dirais que la promotion entière normale est appliquée à a . La norme C ne fournit pas de règles spécifiques pour la conversion de la partie entière d’une opération arithmétique sur un pointeur.

Autrement dit, lorsqu’un caractère est déclaré, il est converti en un int avant d’être passé à l’opérateur + .

Si on ajoute un size_t il rest ce que size_t est défini ou si (pour quelque raison que ce soit) il a un rang plus petit, alors int est promu à un int .

Oui, il est spécifié dans la norme C ++ (paragraphe 1 section 5.7 Opérateurs additifs) que

les conversions arithmétiques habituelles sont effectuées pour des opérandes de type arithmétique ou énumération.

Pour les types (par exemple, char ou unsigned char) dont le rang est inférieur à int, la promotion intégrale sera effectuée. Pour size_t (size_t a un rang qui n’est pas inférieur au rang int ou unsigned int), rien ne sera fait car il n’y a pas de second opérande de type arithmétique.