Подтвердить что ты не робот

Ptrdiff_t слишком мал?

Я всегда задавался вопросом: не означает ли ptrdiff_t удержать разницу в двух указателях по определению? Как это происходит, когда два указателя слишком далеко? (Я не указываю на какой-либо конкретный язык... Я имею в виду все языки, которые имеют этот тип.)

(например, вычтите указатель с адресом 1 из указателя байта с адресом 0xFFFFFFFF, когда у вас есть 32-битные указатели, и он переполнит бит знака...)

4b9b3361

Ответ 1

Нет, это не так.

$5.7 [expr.add] (от n3225 - С++ 0x FCD)
Когда два указателя на элементы одного и того же объекта массива вычитаются, результатом является разность индексов двух элементов массива. Тип результата - это определенный тип интегрированного интегрального типа; этот тип должен быть того же типа, что и std::ptrdiff_t в заголовке <cstddef> (18.2). Как и при любом другом арифметическом переполнении, если результат не соответствует указанному пространству, поведение undefined. Другими словами, если выражения P и Q указывают соответственно на i -th и j -th элементы объекта массива, выражение (P)-(Q) имеет значение i − j, если значение подходит для объекта типа std::ptrdiff_t. Более того, если выражение P указывает либо на элемент объекта массива, либо мимо последнего элемента объекта массива, а выражение Q указывает на последний элемент одного и того же объекта массива, выражение ((Q)+1)-(P) имеет такое же значение, как ((Q)-(P))+1 и как -((P)-((Q)+1)), и имеет значение 0, если выражение P указывает один за последним элементом объекта массива, хотя выражение (Q)+1 не указывает на элемент объект массива. Если оба указателя не указывают на элементы одного и того же объекта массива или один за последним элементом объекта массива, поведение undefined.

Обратите внимание, что в абзаце появляется количество раз undefined. Также обратите внимание, что вы можете только вычитать указатели, если они указывают внутри одного и того же объекта.

Ответ 2

Нет, потому что нет никакой разницы между "любыми двумя указателями". Вы можете только вычитать указатели на элементы одного и того же массива (или указатель на местоположение, расположенное за концом массива).

Ответ 3

Чтобы добавить более явную стандартную цитату, ISO 9899:1999 §J.2/1 заявляет:

Поведение undefined в следующих случаях:

[...]

- Результат вычитания двух указателей не представляется в объекте типа ptrdiff_t (6.5.6).

Ответ 4

Для ptrdiff_t вполне допустимо, чтобы он был того же размера, что и типы указателей, если семантика переполнения определена компилятором, так что любая разница все еще представляется. Нет никакой гарантии, что отрицательный ptrdiff_t означает, что второй указатель живет с более низким адресом в памяти, чем первый, или что ptrdiff_t подписан вообще.

Ответ 5

Over/underflow математически хорошо определен для целочисленной арифметики фиксированного размера:

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

Это правильный результат!

В частности, результат после over/underflow является псевдонимом правильного целого. На самом деле, каждое не представимое целое число является псевдонимом (неразличимым) с одним представляемым целым числом - счетчиком до бесконечности в целых числах фиксированного размера, и вы будете повторяться, круглые и круглые, как набор аналоговых часов.

N-разрядное целое представляет любое действительное целое число по модулю 2 ^ N. В C по модулю 2 ^ N записывается как% (1 < 32).

Я считаю, что C гарантирует математическую корректность over/underflow, но только для целых чисел без знака. Предполагается, что под/переполнением никогда не будет (ради оптимизации).

На практике целые числа со знаком являются двумя дополнениями, что не делает различий в добавлении или вычитании, поэтому правильное поведение при переполнении также гарантируется для целых чисел со знаком (хотя и не с помощью C).