Что такое строковые литералы в C и C ++?

Какой тип строкового литерала в C? Это char *, const char * или const char * const?

А как насчет C ++?


person missingfaktor    schedule 11.02.2010    source источник


Ответы (4)


В C типом строкового литерала является char[] - это не const в зависимости от типа, но это неопределенное поведение для изменения содержимого. Кроме того, два разных строковых литерала с одинаковым содержимым (или достаточным количеством одного и того же содержимого) могут или не могут использовать одни и те же элементы массива.

Из стандарта C99 6.4.5 / 5 «Строковые литералы - семантика»:

На этапе трансляции 7 байт или код нулевого значения добавляется к каждой многобайтовой символьной последовательности, которая получается из строкового литерала или литералов. Затем многобайтовая последовательность символов используется для инициализации массива статической продолжительности хранения и длины, достаточной для хранения последовательности. Для литералов символьной строки элементы массива имеют тип char и инициализируются отдельными байтами многобайтовой последовательности символов; для широких строковых литералов элементы массива имеют тип wchar_t и инициализируются последовательностью широких символов ...

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

В C ++: «Обычный строковый литерал имеет тип 'array of n const char'» (из 2.13.4 / 1 «Строковые литералы»). Но в стандарте C ++ есть особый случай, когда указатель на строковые литералы легко преобразуется в указатели, не квалифицированные константой (4.2 / 2 «Преобразование массива в указатель»):

Строковый литерал (2.13.4), который не является широким строковым литералом, может быть преобразован в rvalue типа «указатель на char»; широкий строковый литерал может быть преобразован в rvalue типа «указатель на wchar_t».

В качестве побочного примечания - поскольку массивы в C / C ++ легко конвертируются в указатели, строковый литерал часто может использоваться в контексте указателя, как и любой массив в C / C ++.


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

Я думаю, что стандарт C решил сделать строковые литералы неконстантными типами, потому что было (и есть) так много кода, который ожидает, что сможет использовать неконстантные указатели char, которые указывают на литералы. Когда был добавлен квалификатор const (что, если я не ошибаюсь, было сделано во время стандартизации ANSI, но спустя много времени после того, как K&R C собрал тонну существующего кода), если они сделали указатели на строковые литералы, которые можно было назначать только к char const* типам без приведения типов почти каждая существующая программа потребовала бы изменения. Не лучший способ добиться принятия стандарта ...

Я считаю, что изменение в C ++, в котором строковые литералы квалифицируются const, было сделано в основном для поддержки того, чтобы буквальная строка могла более точно соответствовать перегрузке, которая принимает аргумент «char const*». Я думаю, что было также желание закрыть кажущуюся дыру в системе типов, но эта дыра в значительной степени была открыта за счет особого случая преобразования массива в указатель.

В приложении D к стандарту указано, что «неявное преобразование из const в неконстантную квалификацию для строковых литералов (4.2) устарело», но я думаю, что так много кода все равно сломается, что пройдет много времени, прежде чем разработчики компилятора или комитет по стандартам готов фактически закрыть пробку (если не будет изобретен какой-нибудь другой умный метод - но тогда дыра вернется, не так ли?).

person Michael Burr    schedule 11.02.2010

Строковый литерал C имеет тип char [n], где n равно количеству символов + 1 для учета неявного нуля в конце строки.

Массив будет размещен статически; это не const, но его изменение - неопределенное поведение.

Если бы он имел тип указателя char * или неполный тип char [], sizeof не мог бы работать должным образом.

Создание строковых литералов const - это идиома C ++, а не часть какого-либо стандарта C.

person Christoph    schedule 11.02.2010

По разным историческим причинам строковые литералы всегда имели тип char[] в C.

Ранее (в C90) было заявлено, что изменение строкового литерала вызывает неопределенное поведение.

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

В языке C этот недостаток все еще присутствует, даже в самом последнем стандарте C.

C ++ унаследовал тот же самый дефект от C, но в более поздних стандартах C ++ они, наконец, сделали строковые литералы const (помечены как устаревшие в C ++ 03, окончательно исправлены в C ++ 11).

person Lundin    schedule 26.04.2016

Раньше они были типа char[]. Теперь они типа const char[].

person 0xfe    schedule 11.02.2010
comment
+1 Указатель .. на что? ГДЕ?? Оооо, вы говорите, КОМПИЛЯТОР творит за меня эту магию. - person Tim Post♦; 11.02.2010
comment
Если вы объявите переменную char [] и установите для нее строковый литерал, вы получите копию этого литерала, которую можно изменить. - person Jay Conrod; 11.02.2010
comment
просто отметим, что после этого изменения было введено стандартное преобразование из const char [] в char []. Это было сделано для того, чтобы не нарушить весь существующий код, в котором были определены функции типа int foo (char *) - person Glen; 11.02.2010
comment
@JayConrod char x[]="abc"; - это особый случай, который объявляет переменную типа char[4] и инициализирует ее, как указано. Это сокращение от char x[4] = {0x61,0x62,0x63,0};, поэтому строковый литерал не обрабатывается так, как другие. В частности, он не будет помещен компилятором в какое-либо безымянное место, как большинство строковых литералов. - person greggo; 01.06.2015
comment
Раньше было когда? Когда это изменилось? - person Ciro Santilli 新疆再教育营六四事件ۍ 21.07.2015
comment
Вы не говорите, имеете ли вы в виду C, но я так полагаю. Стандарты C99 и 2011, кажется, противоречат тому, что вы говорите: C99 6.4.5, §6 говорит: «Если программа пытается изменить такой массив, поведение не определено»; §7 C2011 говорит то же самое. Конечно, здравомыслящие компиляторы (или те, кто заботится о вашем здравомыслии) отметят это за вас, если вы захотите. - person PJTraill; 25.08.2015