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

Есть ли случай, когда "ptr1 - ptr2> 0" будет отличаться от "ptr1> ptr2"?

Предполагая, что два указателя одной и той же точки внутри одного и того же массива (или одного и того же объекта), так что оба вычитания двух указателей и сравнения действительны... есть ли случай, когда

if(ptr1 - ptr2 > 0)

будет отличаться от

if(ptr1 > ptr2)

или они все время эквивалентны?

4b9b3361

Ответ 1

Да, есть такой случай, когда два будут не вести себя одинаково.

Разность указателей подписана [expr.add]:

Когда два указателя на элементы одного и того же объекта массива вычитаются, результатом является разность индексы двух элементов массива. Тип результата представляет собой реализованный по реализации подписанный интеграл тип; этот тип должен быть того же типа, что и std::ptrdiff_t в заголовке <cstddef>

но с двумя оговорками:

Как с любым другим арифметическим переполнением, если результат не соответствует указанному пространству, поведение undefined.

Если оба указателя не указывают на элементы одного и того же объекта массива или один за последним элементом объекта массива, поведение undefined.

На стороне сравнения имеем [expr.rel]:

- Если два указателя указывают на разные элементы одного и того же массива или на его субобъекты, указатель на элемент с более высоким индексом сравнивается больше.
- Если один указатель указывает на элемент массива или на его подобъект и другие указательные точки один за последним элементом массива, последний указатель сравнивается больше.
- Если два указателя указывают на разные нестатические элементы данных одного и того же объекта или на подобъекты таких члены, рекурсивно, указатель на более поздний объявленный элемент сравнивает большее, если два члены имеют одинаковый контроль доступа (раздел 11) и при условии, что их класс не является объединением.

Последняя точка пули дает нам разницу. Рассмотрим:

struct A {
    int x, y;
}

A a;
int *px = &a.x, *py = &a.y

px > py, но px - py > 0 undefined.

Существует также, конечно, целочисленный случай переполнения, если у вас огромный массив:

array[0] > array[PTRDIFF_MAX + 10]         // defined
array[0] - array[PTRDIFF_MAX + 10] > 0     // undefined

Вне этих двух случаев, если два указателя указывают на один и тот же массив (или один на один конец), эти два выражения эквивалентны. Если два указателя указывают на разные массивы, то оба они undefined.

Ответ 2

Конструкции типа if(ptr1 - ptr2 > 0) могут быть опасны.

В последнее время у меня возникла проблема, когда у меня было два указателя для ввода T:

T* p1;
T* p2;

и

sizeof(T) = 16

Теперь была ошибка: разница между p1 и p2 была меньше 16. Итак, p1 - p2 дал 0, что вызвало много ошибок!

Попробуйте этот образец.

Лучшим решением является использование:

if(ptr1 > ptr2)

или

ptrdiff_t diff = (ptrdiff_t)p2 - (ptrdiff_t)p1;

if(diff > 0)
{
}

Итак, в основном, эти две конструкции могут быть или не быть эквивалентными (в зависимости от знака разницы), но иногда они могут работать не так.

Арифметика указателей может быть очень подвержена ошибкам.

Ответ 3

В 32-битной системе вы можете выделить массив из более чем 2 ГБ и иметь два указателя на начало и конец массива, размер которых превышает 2 ГБ.

В этом случае (ptr1 > ptr2) даст результат true, а (ptr1 - ptr2 > 0) будет undefined, если ptrdiff_t является 32-битным целым числом.

(Теперь, поскольку люди редко это делают, есть небольшая вероятность, что ptr1 > ptr2 может дать неправильный результат из-за ошибки компилятора. Если у вас есть два int * более 2 ГБ друг от друга, ptr1-ptr2 будет определяться поведением, потому что правильный результат вписывается в 32-битный номер подписки, но я не удивлюсь, если компилятор ошибся).

Ответ 4

Это зависит от того, как вы выполняете вычитание между ptr1 и ptr2. Если он подписан, тогда он должен работать нормально, иначе, если он неподписан, результат может быть другим. Например, когда:

if (ptr1 > ptr2)

произойдет сбой и вычитание:

ptr1 - ptr2

без знака результат вычитания будет положительным, поэтому:

if (ptr1 - ptr2 > 0)

будет истинным.

Я бы рекомендовал использовать ptr1 > ptr2, потому что он менее подвержен ошибкам и ошибкам.