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

В C, константные переменные гарантированно различаются по памяти?

Говоря о строковых литералах, в стандарте C99 говорится (6.4.5.6):

Не указано, являются ли эти массивы различными, если их элементы имеют соответствующие значения. Если программа пытается изменить такой массив, поведение undefined.

Я не мог найти ни похожего предупреждения, ни явной гарантии для константных переменных. Может ли выражение &x == &y в контексте const int x=12; const int y=12; оцениваться на 1? Что относительно константной переменной и строкового литерала (т.е. &x == "\014\000\000" гарантированно будет 0 даже на 32-битной платформе с маленькими терминами)?

Для чего это стоит, раздел "Строковые литералы" в этот пост в блоге дает контекст вопроса.

4b9b3361

Ответ 1

В стандарте, равенство обсуждается в п. 6.5.9. "Операторы равенства", & обсуждается в п. 6.5.3.2 "Операторы адреса и косвенности", а const обсуждается в п. 6.7.3 "Тип классификаторы". Соответствующий отрывок о равенстве указателя равен §6.5.9.6:

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

Единственное определение & заключается в том, что "Унарный оператор & выводит адрес своего операнда. [...] Результат - это указатель на объект или функцию, назначенные его операндом". (§6.5.3.2.3). К сожалению, формального определения слова "адрес" нет; но разные объекты (для равенства, определенные ==) имеют разные адреса, потому что адреса являются указателями, которые отличаются от определения равенства выше.

Что касается значения const, то в §6.7.3 не указывается, что const имеет какое-либо отношение к тому, что делает объект (который является "областью хранения данных в среде исполнения, содержимое которой может представлять значения" в п. 3.4). Кроме того, сноска указывает, что "для реализации не требуется выделять хранилище для такого объекта, если его адрес никогда не используется". Хотя это ненормативно, это убедительное указание, что если адрес используется, то для каждого объекта должно быть выделено хранилище.

Обратите внимание, что если объекты const volatile, то это довольно ясно (так ясно, как volatile когда-либо), что они не могут иметь один и тот же адрес, потому что объекты const volatile изменяются реализацией. (В §6.7.3.10 приведен пример использования const volatile.)

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

Если речь идет о написании программы на C, вы можете увеличить свои шансы, предоставив объектам разные значения:

const int x = __LINE__;
const int y = __LINE__;

Если речь идет о теоретической модели C, я бы решил сделать объекты разными. Вы должны будете обосновать этот выбор, обобщая ответы здесь в абзаце в (расширенной версии) вашей статьи.

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

(Ссылки из N1256 a.k.a. C99 + TC3. Я не думаю, что версия имеет значение.)

Ответ 2

Насколько мне известно, Стандарт не позволяет двум именованным объектам любого типа иметь один и тот же адрес (кроме членов объединения). Из пункта 6.5.9/6:

Два указателя сравнивают равные, если и только если оба являются нулевыми указателями, то оба указатели на один и тот же объект...

Строковые литералы не являются константными переменными, поэтому ваш вторичный вопрос является спорным, и я не вижу, что с ним связано 32-битность и сущность.

Ответ 3

В

const int x=12;
const int y=12;

x и y - это разные переменные (как const-qual), так и разные адреса.

То же самое для другого примера.

Обратите внимание, что const является квалификатором для объекта. Что касается макета памяти, это не имеет значения, если он есть или нет.

Ответ 4

6.4.5/6 говорит о массивах, соответствующих строковым литералам:

Неясно, являются ли эти массивы отличаются друг от друга своими элементами имеют соответствующие значения.

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