Адрес строкового литерала в единицах перевода [дубликат]
этот вопрос уже есть ответ здесь:
- адреса двух указателей же 10 ответов
Я хотел бы спросить, Можно ли полагаться на строковый литеральный адрес в единицах перевода? Т. е.:
файл foo.c
имеет ссылку на строковый литерал "I'm a literal!"
, это правильно и портативный полагаться на это в другом данном файле,bar.c
в частности, что тот же строковый литерал "I'm a literal!"
будет тот же адрес памяти? Считая, что каждый файл будет переведен на индивидуальный .
для лучшей иллюстрации, пример кода:
# File foo.c
/* ... */
const char * x = "I'm a literal!"
# File bar.c
/* ... */
const char * y = "I'm a literal!"
# File test.c
/* ... */
extern const char * x;
extern const char * y;
assert (x == y); //Is this assertion going to fail?
и пример командной строки gcc:
gcc -c -o foo.o -Wall foo.c
gcc -c -o bar.o -Wall bar.c
gcc -c -o test.o -Wall test.c
gcc -o test foo.o bar.o test.o
как насчет в том же блоке перевода? Будет ли это надежно, если строковые литералы находятся в то же самое единица перевода?
2 ответов
вы не можете полагаться на идентичные строковые литералы имея такое же расположение памяти, это решение о реализации. The проект стандарта C99 сообщает нам, что не указано, является ли один и тот же строковый литерал отличным от раздела 6.4.5
строковые литералы:
не указано, являются ли эти массивы различными при условии, что их элементы имеют соответствующие значения. Если программа пытается изменить такой массив, поведение не определено.
для C++ это описано в разделе проекта стандарта 2.14.5
строковые литералы Он говорит:
все ли строковые литералы различны (то есть хранятся в nonoverlapping objects) определяется реализация. Влияние попытка изменить строковый литерал не определена.
компилятору разрешено бассейн строковые литералы, но вам придется поймите, как он работает от компилятора к компилятору, и поэтому это не будет переносимым и может потенциально измениться. Visual Studio включает в себя опция для пула строковых литералов
в некоторых случаях для экономии места могут быть объединены одинаковые строковые литералы в исполняемом файле. В пуле строковых литералов компилятор вызывает все ссылки на конкретного строкового литерала то же расположение в памяти, вместо того чтобы каждую контрольную точку в отдельный экземпляр строкового литерала. Чтобы включить пул строк, используйте параметр компилятора /GF.
обратите внимание, что он имеет право с В некоторых случаях.
gcc
поддерживает объединение в пул и между единицами компиляции, и вы можете включить его через -fmerge-константы:
попытка объединить одинаковые константы (строковые константы и константы с плавающей запятой) в единицах компиляции.
этот параметр является значением по умолчанию для оптимизированной компиляции, если ассемблер и linker поддерживает его. Используйте-fno-merge-константы для ингибирования этого поведение.
Примечание, использование попытка и если ... поддержки.
что касается обоснования, по крайней мере, для C для не требующего строковые литералы для объединения мы можем видеть из этого архивные комп.станд.c обсуждение строковых литералов что обоснование было связано с широким разнообразие реализации в то время:
GCC мог бы служить примером, но не мотивацией. Частично желание иметь строковые литералы в ROMmable данных было поддержать, er, ROMming. Я смутно помню, что использовал пару реализаций C (до принятия решения X3J11), где строковые литералы были либо автоматически объединяется или хранится в разделе постоянной программы данных. Учитывая существующее разнообразие практики и наличие легкого работа вокруг, когда исходные свойства UNIX были нужны, казалось лучше не пытаться гарантировать уникальность и записываемость строки константы.
нет, вы не можете ожидать тот же адрес. Если это случится, то случится. Но ничего не помогает.
§ 2.14.5 / p12
все ли строковые литералы различны (то есть хранятся в nonoverlapping objects) определяется реализация. Влияние попытка изменить строковый литерал не определена.
компилятор может делать все, что ему заблагорассудится. Они могут храниться в разных местах, если они находятся в разных единицы перевода или даже если они находятся в одной и той же единице перевода, независимо от того, что они являются памятью только для чтения.
в MSVC, например, адреса в обоих случаях совершенно разные, но опять же: ничто не мешает компилятору объединять значения указателей (даже здесь, поскольку ограничение раздела только для чтения обязательно).