ptrdiff_t trop petit?

Je me suis toujours demandé: ptrdiff_t n’est-il pas censé être capable de maintenir la différence entre deux indicateurs par définition ? Comment se fait-il qu’il échoue quand les deux pointeurs sont trop loin? (Je ne pointe pas une langue en particulier … Je parle de toutes les langues qui ont ce type.)

(par exemple, soustrayez le pointeur avec l’adresse 1 du pointeur d’octet avec l’adresse 0xFFFFFFFF lorsque vous avez des pointeurs 32 bits, et le dépassement du bit de signe …)

Non ce n’est pas.

$ 5.7 [expr.add] (à partir de n3225 – C ++ 0x FCD)
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 identique à celui défini comme std::ptrdiff_t dans l’en-tête (18.2). Comme pour tout autre dépassement arithmétique, si le résultat ne rentre pas dans l’espace prévu, le comportement n’est pas défini. En d’autres termes, si les expressions P et Q pointent respectivement vers les éléments i th et j -th d’un object tableau, l’expression (P)-(Q) a la valeur i − j condition que la valeur s’insère dans un object de type std::ptrdiff_t . De plus, si l’expression P pointe sur un élément d’un object tableau ou après le dernier élément d’un object tableau et que l’expression Q pointe sur le dernier élément du même object tableau, l’expression ((Q)+1)-(P) a la même valeur que ((Q)-(P))+1 et que -((P)-((Q)+1)) , et a la valeur zéro si l’expression P pointe un après le dernier élément de l’object tableau même si l’expression (Q)+1 ne pointe pas vers un élément de l’object tableau. À moins que les deux pointeurs pointent vers des éléments du même object de tableau ou derrière le dernier élément de l’object de tableau, le comportement est indéfini.

Notez le nombre de fois undefined apparaît dans le paragraphe. Notez également que vous ne pouvez soustraire des pointeurs que s’ils pointent dans le même object.

Non, car la différence entre “deux pointeurs” n’existe pas. Vous pouvez uniquement soustraire des pointeurs sur des éléments du même tableau (ou le pointeur sur l’emplacement situé juste après la fin d’un tableau).

Pour append une citation standard plus explicite, ISO 9899:1999 §J.2/1 :

Le comportement n’est pas défini dans les cas suivants:

[…]

– Le résultat de la soustraction de deux pointeurs n’est pas représentable dans un object de type ptrdiff_t (6.5.6).

Il est tout à fait acceptable que ptrdiff_t ait la même taille que les types de pointeur, à condition que la sémantique de débordement soit définie par le compilateur, de sorte que toute différence soit toujours représentable. Rien ne garantit qu’un ptrdiff_t négatif signifie que le deuxième pointeur vit à une adresse mémoire inférieure au premier, ou que ptrdiff_t est signé.

Le dépassement / le dépassement est mathématiquement bien défini pour l’arithmétique des entiers de taille fixe:

 (1 - 0xFFFFFFFF) % (1<<32) = (1 + -0xFFFFFFFF) % (1<<32) = 1 + (-0xFFFFFFFF % (1<<32)) = 2 

C'est le bon résultat!

Plus précisément, le résultat après dépassement / dépassement est un alias du nombre entier correct. En fait, chaque entier non représentable est aliasé (indiscernable) avec un entier représentable - compter à l'infini dans des entiers de taille fixe, et vous vous répéterez tour à tour comme un cadran d'horloge analogique.

Un entier de N bits représente tout entier réel modulo 2 ^ N. En C, modulo 2 ^ N est écrit sous la forme% (1 << 32).

Je crois que C garantit l'exactitude mathématique du dépassement supérieur / inférieur, mais uniquement pour les entiers non signés. Le dépassement / dépassement de capacité signé est supposé ne jamais se produire (dans un souci d'optimisation).

En pratique, les entiers signés sont des compléments à deux, ce qui ne fait aucune différence en addition ou en soustraction. Par conséquent, un comportement correct de sous-débordement / débordement est garanti pour les entiers signés aussi (mais pas par C).