В C гарантированы ли постоянные переменные в памяти? - PullRequest
11 голосов
/ 04 июня 2011

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

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

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

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

Ответы [ 4 ]

6 голосов
/ 04 июня 2011

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

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

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

5 голосов
/ 04 июня 2011

В стандарте равенство обсуждается в §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.14). Далее в сноске указывается, что «реализация не должна выделять память для такого объекта, если его адрес никогда не используется». Хотя это ненормативно, это сильный признак того, что если адрес используется, то для каждого объекта должно быть выделено хранилище .

Обратите внимание, что если объекты 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. Я не думаю, что версия имеет значение.)

3 голосов
/ 04 июня 2011

В

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

x и y - это разные переменные (обе с константной квалификацией), поэтому они имеют разные адреса.

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

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

1 голос
/ 04 июня 2011

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

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

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

...