ptrdiff_t слишком маленький? - PullRequest
       11

ptrdiff_t слишком маленький?

17 голосов
/ 01 февраля 2011

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

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

Ответы [ 5 ]

28 голосов
/ 01 февраля 2011

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

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

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

8 голосов
/ 01 февраля 2011

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

2 голосов
/ 27 октября 2011

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

Поведение не определено в следующих обстоятельствах:

[...]

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

1 голос
/ 01 февраля 2011

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

0 голосов
/ 17 мая 2013

Переполнение / недостаточность математически правильно определены для целочисленной арифметики фиксированного размера:

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

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

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

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

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

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

...