Est-il même possible que le résultat de i-j
de ne pas être dans la gamme des valeurs représentables de ptrdiff_t
?
Oui, mais c'est peu probable.
En fait, [support.types.layout]/2
ne dit pas grand chose, si ce n'est les règles appropriées concernant la soustraction des pointeurs et la ptrdiff_t
sont définis dans [expr.add]
. Voyons donc cette section.
Lorsque deux pointeurs sur des éléments du même objet tableau sont soustraits, le type du résultat est un type d'intégrale signée défini par l'implémentation ; ce type doit être le même que celui qui est défini comme suit std::ptrdiff_t
dans le <cstddef>
en-tête.
Tout d'abord, notez que le cas où i
y j
sont des indices d'indices de tableaux différents n'est pas prise en compte. Cela permet de traiter i-j
comme P-Q
serait où P
est un pointeur sur l'élément d'un tableau à l'indice i
y Q
est un pointeur vers l'élément de le même tableau à l'indice j
. En effet, la soustraction de deux pointeurs sur des éléments de tableaux différents est comportement indéfini :
Si les expressions P
y Q
pointent, respectivement, vers les éléments x[i]
y x[j]
du même objet du tableau x
l'expression P - Q
a la valeur ij
; sinon, le comportement est indéfini .
En conclusion, avec la notation définie précédemment, i-j
y P-Q
sont définis pour avoir la même valeur, cette dernière étant de type std::ptrdiff_t
. Mais rien n'est dit sur la possibilité pour ce type de détenir une telle valeur. Il est toutefois possible de répondre à cette question à l'aide des éléments suivants std::numeric_limits
; en particulier, on peut détecter si un tableau some_array
est trop grand pour std::ptrdiff_t
pour contenir toutes les différences d'index :
static_assert(std::numeric_limits<std::ptrdiff_t>::max() > sizeof(some_array)/sizeof(some_array[0]),
"some_array is too big, subtracting its first and one-past-the-end element indexes "
"or pointers would lead to undefined behavior as per [expr.add]/5."
);
Maintenant, sur une cible habituelle, cela n'arriverait généralement pas car sizeof(std::ptrdiff_t) == sizeof(void*)
ce qui signifie qu'un tableau devrait être stupidement grand pour que les ptrdiff_t
pour déborder. Mais il n'y a aucune garantie de cela.
1 votes
Sur de nombreuses architectures populaires (la plupart des plates-formes <=32 bits), il serait plutôt difficile et coûteux de fournir un ptrdiff_t qui puisse toujours contenir
i-j
(et ils ne fournissent pas en fait un tel ptrdiff_t). L'intention de la norme n'est pas de rendre les choses difficiles et coûteuses, ou de rendre la plupart des implémentations existantes non conformes, mais plutôt l'inverse. Donc oui, il "peut faire la différence"... quand il le peut.0 votes
Oui, la deuxième citation dit que - si
i
yj
sont des indices valides pour le même tableau, qu'unptrdiff_t
peut représenter le résultat dei - j
. La première citation revient à l'exigence inverse, à savoir quei - j
doit également pouvoir être représentée dans unptrdiff_t
ou le comportement n'est pas défini (je dirais que la première note est redondante étant donné la présence de la seconde, mais elle réduit probablement les possibilités pour les juristes linguistiques de trouver des failles obscures exploitables dans le langage).0 votes
Une chose qui est implicite est que, d'après ce que j'ai compris, les problèmes ne peuvent survenir que s'il s'agit d'un tableau d'un type avec sizeof=1 (comme char). (Ou existe-t-il un cas particulier pour sizeof=2 également ?).