Это неопределенное поведение для сравнения указателей на разные массивы на равенство? - PullRequest
16 голосов
/ 06 февраля 2011

Операторы равенства имеют семантические ограничения операторов отношений на указатели:

Операторы == (равно) и! = (Не равно) имеют те же семантические ограничения, преобразования и тип результата, что и операторы отношения, за исключением их более низкого приоритета и результата истинности-значения. [C ++ 03 §5.10p2]

А у реляционных операторов есть ограничение на сравнение указателей:

Если два указателя p и q одного и того же типа указывают на разные объекты, которые не являются членами одного и того же объекта или элементов одного и того же массива или на разные функции, или если только один из них равен нулю, результаты p < q, p> q, p <= q и p> = q не определены. [§5.9p2] * * +1010

Это семантическое ограничение, которое "наследуется" операторами равенства?

В частности, учитывая:

int a[42];
int b[42];

Понятно, что (a + 3) <(b + 3) не определено, но (a + 3) == (b + 3) также не определено? </p>

Ответы [ 3 ]

16 голосов
/ 06 февраля 2011

Семантика для op== и op!= явно говорит о том, что отображение равно , за исключением результата с истинным значением .Таким образом, вам нужно посмотреть, что определено для их истинного значения результата.Если они говорят, что результат не указан, то он не указан.Если они определяют конкретные правила, то это не так.В частности, говорится:

Два указателя одного типа сравниваются равными, если и только если они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес

11 голосов
/ 06 февраля 2011

Результат от операторов равенства (== и !=) дает указанные результаты, если указатели относятся к объектам одного типа.Учитывая два указателя на один и тот же тип, верно одно из следующих утверждений:

  1. оба являются нулевыми указателями и сравниваются равными друг другу.
  2. оба являются указателями на один и тот жеобъект, и они сравниваются равными друг другу.
  3. они являются указателями на разные объекты, и они сравниваются не равны друг другу.
  4. по крайней мере один не инициализируется, и результатсравнение не определено (и, собственно, само сравнение может никогда не произойти - просто попытка прочитать указатель, чтобы выполнить сравнение, дает неопределенное поведение).

При одинаковых ограничениях (оба указателя)относятся к объекту одного типа) результат от операторов упорядочения (<, <=, >, >=) указывается только в том случае, если оба они являются указателями на один и тот же объект или на отдельные объекты втот же массив (и для этой цели «кусок» памяти, выделенный с помощью malloc, new и т. д., квалифицируется как массив).Если указатели ссылаются на отдельные объекты, которые не являются частью одного и того же массива, результат не определен.Если один или оба указателя не были инициализированы, у вас неопределенное поведение.

Несмотря на это, однако, шаблоны сравнения в стандартной библиотеке (std::less, std::greater, std::less_equal и std::greater_equal) do все дают значимый результат, даже если / если встроенные операторы этого не делают.В частности, они обязаны давать общий заказ.Таким образом, вы можете получить порядок, если хотите, но только не с помощью встроенных операторов сравнения (хотя, конечно, если один или оба указателя не инициализированы, поведение по-прежнему не определено).

6 голосов
/ 06 февраля 2011

Поскольку существует путаница в семантике соответствия, это правила для C ++. C использует совершенно другую модель соответствия.

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

  2. Плохо сформированная программа означает, что, если не указано иное, поведение переводчика жестко определено: требуется отклонить вашу программу и выдать диагностическое сообщение. Основным особым случаем здесь является Правило единого определения, если вы нарушаете, что ваша программа некорректна, но диагностика не требуется.

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

  4. Unspecified - это глупый термин, который означает, что поведение происходит из набора. В этом смысле четко определенный просто особый случай, когда набор разрешенных поведений содержит только один элемент. Unspecified не требует документации, поэтому в некотором смысле это также означает то же самое, что и реализация, определенная без документации.

В целом, стандарт C ++ не является языковым стандартом, это модель для языкового стандарта. Чтобы сгенерировать актуальный стандарт, вы должны подключить различные параметры. Самым простым из них является ограничение, определяемое реализацией.

В Стандарте есть пара глупых конфликтов, например, законный переводчик может отклонить каждую явно хорошую программу на C ++ на том основании, что вам необходимо предоставить функцию main(), но переводчик поддерживает только идентификаторы из 1 символа. , Эта проблема решается понятием QOI или качеством реализации. В основном говорится, кого это волнует, никто не собирается покупать этот компилятор только потому, что он соответствует.

Технически, неопределенная природа operator <, когда указатели относятся к несвязанным объектам, вероятно, имеет в виду: вы получите какой-то результат, который будет либо истинным, либо ложным, но ваша программа не будет аварийно завершена, однако это не правильно значение «неопределенное», то есть дефект: «неопределенное» наложило на авторов стандартов бремя документирования набора разрешенных вариантов поведения , поскольку, если набор открыт, то он эквивалентен неопределенному поведению.

Я фактически предложил std::less в качестве решения проблемы, согласно которой некоторые структуры данных требуют, чтобы ключи были полностью упорядочены, но указатели не полностью упорядочены по operator <. На большинстве машин с использованием линейной адресации less совпадает с <, но операция less, скажем, на процессоре x86 потенциально более дорогая.

...