Адрес строкового литерала в единицах перевода [дубликат]

этот вопрос уже есть ответ здесь:

Я хотел бы спросить, Можно ли полагаться на строковый литеральный адрес в единицах перевода? Т. е.:

файл 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, например, адреса в обоих случаях совершенно разные, но опять же: ничто не мешает компилятору объединять значения указателей (даже здесь, поскольку ограничение раздела только для чтения обязательно).