В чем обоснование ограничений на арифметику или сравнение указателя?

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

В чем причины таких ограничений?

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

Ответ 1

Существуют архитектуры, где пространство программ и данных разделено, и просто невозможно вычесть два произвольных указателя. Указатель на функцию или на константные статические данные будет находиться в совершенно другом адресном пространстве, чем обычная переменная.

Даже если вы произвольно поставили рейтинг между разными адресными пространствами, существует вероятность того, что тип diff_t должен быть большего размера. И процесс сравнения или вычитания двух указателей будет очень сложным. Это плохая идея на языке, который предназначен для скорости.

Ответ 2

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

В частности, разница должна иметь тип, который является ptrdiff_t, и можно предположить, что он похож на size_t.

В сегментированной модели памяти вы (обычно) косвенно имеете ограничение на размеры объектов - при условии, что ответы в: Каков реальный размер` size_t`, `uintptr_t`, `intptr_t` и` ptrdiff_t` в 16-разрядных системах с использованием режима сегментированной адресации?.

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

C был разработан как более минималистический, а не для того, чтобы заставить компилятор тратить память и код на такие случаи. (В те времена ограничения памяти имели большее значение.)

Очевидно, есть и другие преимущества - например, возможность обнаружения ошибок при смешивании указателей из разных массивов. Аналогично смешиванию итераторов для двух разных контейнеров undefined в С++ (с некоторыми незначительными исключениями) - и некоторые отладочные реализации обнаруживают такие ошибки.

Ответ 3

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

Ограничения, налагаемые стандартом, позволяют компилятору делать предположения об арифметике указателя и использовать это для улучшения качества кода. Он охватывает как вычислительные вещи статически в компиляторе, а не во время выполнения и выбирает, какие режимы и режимы адресации использовать. В качестве примера рассмотрим программу с двумя указателями p1 и p2. Если компилятор может определить, что они указывают на разные объекты данных, можно с уверенностью предположить, что любая операция no, основанная на следующем p1, никогда не повлияет на объект, на который указывает p2. Это позволяет компилятору переупорядочивать нагрузки и хранилища на основе p1 без учета загрузок и хранилищ на основе p2 и наоборот.

Ответ 4

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

Это возвращается полностью к стандартным C. Обоснование C не упоминает об этом явно, но это намекает на то, что это причина, если мы посмотрим, где это объясняет обоснование, почему использование индекса отрицательного массива undefined поведение (соображение C99 5.10 6.5.6, акцент мой):

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

Ответ 5

Поскольку стандарт C предназначен для покрытия большинства процессорных архитектур, он должен также охватывать этот: Представьте себе архитектуру (я знаю ее, но не назову ее), где указатели - это не просто простые числа, а как структуры или "дескрипторы". Такая структура содержит информацию об объекте, на который он указывает (его виртуальный адрес и размер), и смещение внутри него. Добавление или вычитание указателя создает новую структуру с измененным только полем смещения; создание структуры со смещением, большим, чем размер объекта, запрещено аппаратным обеспечением. Существуют и другие ограничения (например, как создается исходный дескриптор или каковы другие способы его изменения), но они не имеют отношения к теме.

Ответ 6

Я хотел бы ответить на это, обратив вопрос. Вместо того, чтобы спрашивать, почему добавление указателя и большинство арифметических операций не разрешены, почему указатели допускают только добавление или вычитание целых чисел, столбцов и предварительных приращений и декрементов и сравнения (или вычитания) указателей, указывающих на один и тот же массив? Это связано с логическим следствием арифметической операции. Добавление/вычитание целого числа n в указатель p дает мне адрес n-го элемента из текущего элемента в прямом или обратном направлении. Точно так же вычитание p1 и p2, указывающих на один и тот же массив, дает мне количество элементов между двумя указателями. Факт (или дизайн), согласно которому арифметические операции указателя согласованы с типом переменной, на которую он указывает, является настоящим гением. Любая операция, отличная от разрешенных, бросает вызов программированию или философски логическим рассуждениям и поэтому не допускается.

Ответ 7

(Пожалуйста, не повысьте). Это краткое изложение ответа, и причина, по которой я выбрал ответ Mark Ransom, и сделать это сообщение: ответ - это его пост + следующий комментарий.

Вопрос: Каковы причины таких ограничений (что арифметика указателей и сравнение должны падать на уникальный полный объект)?

Комментарий о выкупе + комментарий: поскольку нет понятия адресного пространства, единственная возможность ограничить арифметику указателя, которая попадает внутрь адресного пространства, заключалась в том, чтобы ограничить его на объекте.

Комментарий Krazy Glew также обеспечивает социологический ориентированный ответ.