Каков тип строкового литерала в C? Это char *
или const char *
или const char * const
?
Как насчет С++?
Каков тип строкового литерала в C? Это char *
или const char *
или const char * const
?
Как насчет С++?
В C тип строкового литерала - это char[]
- it not const
в соответствии с типом, но это поведение undefined для изменения содержимого. Кроме того, 2 разных строковых литерала, которые имеют один и тот же контент (или достаточно одного и того же контента), могут или не могут совместно использовать одни и те же элементы массива.
Из стандарта C99 6.4.5/5 "Строковые литералы - семантика":
В фазу 7 перевода байта или код нулевого значения добавляется к каждой многобайтовой последовательности символов, которая получается из строкового литерала или литералов. Последовательность многобайтовых символов затем используется для инициализации массива статической продолжительности хранения и длины, достаточной для того, чтобы содержать последовательность. Для символьных строковых литералов элементы массива имеют тип
char
и инициализируются отдельными байтами многобайтовой последовательности символов; для широких строковых литералов элементы массива имеют типwchar_t
и инициализируются последовательностью широких символов...Не указано, являются ли эти массивы различными, если их элементы имеют соответствующие значения. Если программа пытается изменить такой массив, поведение undefined.
В С++ "Обычный строковый литерал имеет тип" массив n const char
"(из 2.13.4/1" Строковые литералы "). Но там есть специальный случай в стандарте С++, который делает указатель на строковые литералы легко преобразовываться в неконвертированные указатели (4.2/2" Преобразование массива в указатель"):
Строковый литерал (2.13.4), который не является широким строковым литералом, может быть преобразован в rvalue типа "указатель на char"; широкий строковый литерал может быть преобразован в rvalue типа "указатель на wchar_t".
Как побочная заметка - потому что массивы в C/С++ так легко конвертируются в указатели, строковый литерал часто может использоваться в контексте указателя, как и любой массив в C/С++.
Дополнительная редакция: то, что следует на самом деле, в основном является предположением с моей стороны о обосновании выбора стандартов C и С++ в отношении типов строковых литералов. Так что возьмите его с солью (но прокомментируйте, если у вас есть исправления или дополнительные данные):
Я думаю, что в стандарте C вы выбрали строковые литералы, не являющиеся константными, потому что было (и есть) столько кода, который рассчитывает использовать неконтекстно-ориентированные указатели char
, которые указывают на литералы. Когда добавлен квалификатор const
(который, если я не ошибаюсь, делался во время стандартизации ANSI, но задолго до того, как K & RC был вокруг, чтобы накопить тонну существующего кода), если они сделали указатели на строковые литералы, быть привязанным к типам char const*
без приведения почти каждой программы, необходимой для изменения. Не лучший способ получить стандартное согласие...
Я считаю, что изменение на С++, что строковые литералы const
квалифицировалось, было сделано главным образом для поддержки допуска к тому, что литеральная строка более соответствовала перегрузке, которая принимает аргумент "char const*
". Я думаю, что было также желание закрыть воспринимаемую дыру в системе типов, но отверстие было в значительной степени открыто резервным копированием в специальном случае в преобразованиях от массива к указателю.
Приложение D стандарта указывает, что "неявное преобразование из const в неконстантную квалификацию для строковых литералов (4.2) устарело", но я думаю, что так много кода все равно сломается, что будет долгое время перед компилятором исполнители или комитет по стандартизации готовы на самом деле вытащить вилку (если не придумать какую-либо другую умную технику), но тогда отверстие вернется, не так ли?).
Строковый литерал C имеет тип char [n]
, где n
равно числу символов + 1 для учета неявного нуля в конце строки.
Массив будет статически распределен; это не const
, но изменение его поведения undefined.
Если у него был тип указателя char *
или неполный тип char []
, sizeof
не мог работать должным образом.
Создание строковых литералов const
- это идиома С++, а не часть любого стандарта C.
Они имели тип char[]
. Теперь они имеют тип const char[]
.
По разным историческим причинам строковые литералы всегда имели тип char[]
в C.
В начале (на C90) было указано, что изменение строкового литерала вызывает поведение undefined.
Они не запрещали такие модификации, хотя и не делали строковых литералов const char[]
, что имело бы больше смысла. Это связано с соображениями обратной совместимости со старым кодом. Некоторые старые ОС (в особенности DOS) не протестовали, если вы модифицировали строковые литералы, поэтому было много такого кода.
C все еще имеет этот дефект сегодня, даже в самом последнем стандарте C.
С++ унаследовал один и тот же самый дефект от C, но в более поздних версиях С++ они, наконец, сделали строковые литералы const
(помечены как устаревшие в С++ 03, наконец, исправлены в С++ 11).