Область (строковых) литералов - PullRequest
29 голосов
/ 06 ноября 2008

Я всегда стараюсь не возвращать строковые литералы, потому что боюсь, что они не определены вне функции. Но я не уверен, что это так. Возьмем, к примеру, эту функцию:


const char *
return_a_string(void)
{
    return "blah";
}

Это правильный код? Это работает для меня, но, возможно, это работает только для моего компилятора (GCC). Поэтому вопрос в том, имеют ли (строковые) литералы область видимости или они присутствуют / определены постоянно.

Ответы [ 7 ]

41 голосов
/ 06 ноября 2008

Этот код подходит для всех платформ. Строка компилируется в двоичный файл как статический строковый литерал. Например, если вы работаете в Windows, вы можете даже открыть свой .exe с помощью блокнота и найти саму строку.

Так как это статическая строка, область литерала не имеет значения.

Объединение строк:

Следует обратить внимание на то, что в некоторых случаях идентичные строковые литералы могут быть «объединены» для экономии места в исполняемом файле. В этом случае каждый строковый литерал, который был тем же самым, мог иметь тот же адрес памяти. Вы никогда не должны предполагать, что это будет или не будет так.

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

Максимальный размер строковых литералов:

У нескольких компиляторов максимальный размер строкового литерала. Например, для VC ++ это примерно 2048 байт.

Изменение строкового литерала дает неопределенное поведение:

Изменение строкового литерала никогда не должно выполняться. У него неопределенное поведение.

char * sz = "this is a test";
sz[0] = 'T'; //<--- undefined results

Широкие строковые литералы:

Все вышесказанное в равной степени относится и к широким строковым литералам.

Пример: L "это широкий строковый литерал";

Стандарт C ++ гласит: (раздел lex.string)

1 Строковый литерал - это последовательность символов (как определено в lex.ccon ) в двойных кавычках, необязательно начиная с буква L, как в «...» или L «...». Строковый литерал, который не начинается с L является обычным строковым литералом, также называемым узким строковый литерал. Обычный строковый литерал имеет тип "массив из n Const char "и статическая продолжительность хранения ( basic.stc ), где n - это размер строки, как определено ниже, и инициализируется с персонажи. Строковый литерал, который начинается с L, такой как L "asdf", является широкий строковый литерал. Широкий строковый литерал имеет тип "массив N const wchar_t "и имеет статическую продолжительность хранения, где n - размер из строка, как определено ниже, и инициализируется с заданным символом Ослабляет.

2 Все ли строковые литералы различны (то есть хранятся в неперекрывающиеся объекты) определяется реализацией. Эффект из попытка изменить строковый литерал не определена.

10 голосов
/ 07 сентября 2011

Я приведу вам пример, чтобы ваше замешательство прояснилось

char *f()
{
char a[]="SUMIT";
return a;
}

это не сработает.

но

char *f()
{
char *a="SUMIT";
return a;
}

это работает.

Причина: «SUMIT» - это литерал, имеющий глобальную область видимости. в то время как массив, который является просто последовательностью символов {'S', 'U', 'M', 'I', 'T' '\ 0'} имеет ограниченную область видимости и исчезает, как только программа возвращается.

Надеюсь, это поможет

5 голосов
/ 07 ноября 2008

Это верно для C (или C ++), как объяснили другие.

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

Стандарт C (или C ++) не понимает и не учитывает загрузку и выгрузку кода во время выполнения, поэтому все, что делает это, повлечет за собой определенные реализацией последствия: в этом случае последствием является строковый литерал, предполагается, что статическая длительность хранения, как видно из POV вызывающего кода, не сохраняется в течение всей продолжительности программы.

3 голосов
/ 06 ноября 2008

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

3 голосов
/ 06 ноября 2008

Да, все в порядке. Они живут в глобальной строковой таблице.

0 голосов
/ 06 ноября 2008

Очень важно отметить неопределенные результаты, упомянутые Брайаном. Поскольку вы объявили функцию как возвращающую тип const char *, у вас все будет в порядке, но на многих платформах строковые литералы помещаются в доступный только для чтения сегмент в исполняемом файле (обычно это текстовый сегмент), и их изменение вызовет нарушение прав доступа. на большинстве платформ.

0 голосов
/ 06 ноября 2008

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

...