Ptrdiff t peut-il représenter toutes les soustractions de pointeurs vers des éléments du même objet de tableau?

pour la soustraction des pointeurs i et j aux éléments du même objet de tableau la note dans [expr.ajouter#5] se lit:

[ Note: Si la valeur i-j n'est pas dans la gamme de représentable, les valeurs de type std​::​ptrdiff_­t , le comportement est indéfini. - note finale ]

mais donné [soutien.type.disposition n ° 2] , qui stipule que ( accent le mien):

  1. le type ptrdiff_­t est un type entier signé défini par implémentation qui peut contenir la différence de deux indices dans un objet array, tel que décrit dans [expr.ajouter] .

est-il même possible pour le résultat de i-j Non être dans l'intervalle des valeurs représentatives de ptrdiff_t ?

PS: je m'excuse si ma question est causée par ma mauvaise compréhension de la langue anglaise.

EDIT: Related: Pourquoi est la taille maximale d'un tableau est "trop grand"?

32
demandé sur jotik 2018-03-20 12:27:29

2 réponses

est-il même possible que le résultat de i-j ne soit pas dans l'intervalle des valeurs représentatives de ptrdiff_t ?

Oui, mais c'est peu probable.

en fait, [support.types.layout]/2 ne dit pas grand chose sauf les règles appropriées sur la soustraction de pointeurs et ptrdiff_t sont définis dans [expr.add] . Donc, nous allons voir cette section.

[expr.add]/5

lorsque deux pointeurs vers des éléments du même objet array sont soustraits, le type du résultat est un type intégral signé défini par implémentation; ce type doit être le même type qui est défini comme std​::​ptrdiff_­t dans l'en-tête <cstddef> .

tout d'abord, notez que le cas où i et j sont des indices en indice de différents tableaux n'est pas considéré. Cela permet de traiter 151910920" P-Q est lorsque P est un pointeur vers l'élément d'un tableau à l'indice i et Q est un pointeur vers l'élément de le même tableau à l'indice j . En effet, soustraire deux pointeurs à des éléments de tableaux différents est comportement non défini :

[expr.add]/5

si les expressions P et Q pointent respectivement vers les éléments x[i] et x[j] du même objet de tableau x , l'expression P - Q a la valeur i−j ; sinon, le comportement est non défini .

comme conclusion, avec la notation définie précédemment, i-j et P-Q sont définis pour avoir la même valeur, ce dernier étant de type std::ptrdiff_t . Mais rien n'est dit sur la possibilité, pour ce type d'organiser une telle valeur. On peut cependant répondre à cette question à l'aide de std::numeric_limits ; en particulier, on peut détecter si un tableau some_array est trop grand pour std::ptrdiff_t pour tenir 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 la cible habituelle, cela ne se produirait généralement pas comme sizeof(std::ptrdiff_t) == sizeof(void*) ; ce qui signifie qu'un tableau devrait être stupidement grand pour ptrdiff_t à débordement. Mais il n'y a aucune garantie.

5
répondu YSC 2018-03-27 15:46:33

je pense que c'est un bug des formulations.

La règle dans [expr.add] est hérité de la même règle pour la soustraction de pointeur dans le standard C. Dans la norme C, ptrdiff_t n'est pas requis pour contenir une différence de deux indices dans un objet array.

La règle [de soutien.type.mise en page] provient de Core Question de la Langue 1122 . Il a ajouté des définitions directes pour std::size_t et std::ptrdiff_t , qui est supposé pour résoudre le problème de la définition circulaire. Je ne vois aucune raison (du moins pas mentionnée dans un document officiel) de faire std::ptrdiff_t tenir une différence de deux indices dans un objet array. Je suppose qu'il utilise une définition incorrecte pour résoudre le problème de la définition circulaire.

Comme une autre preuve, [diff.bibliothèque] ne mentionne aucune différence entre std::ptrdiff_t en C++ et ptrdiff_t en C. Depuis en C ptrdiff_t n'a pas une telle contrainte, en C++ std::ptrdiff_t ne devrait pas avoir une telle contrainte aussi.

1
répondu xskxzr 2018-03-23 15:54:35