Каков тип строковых литералов в C и С++?

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

Как насчет С++?

Ответ 1

В 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) устарело", но я думаю, что так много кода все равно сломается, что будет долгое время перед компилятором исполнители или комитет по стандартизации готовы на самом деле вытащить вилку (если не придумать какую-либо другую умную технику), но тогда отверстие вернется, не так ли?).

Ответ 2

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

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

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

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

Ответ 3

Они имели тип char[]. Теперь они имеют тип const char[].

Ответ 4

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

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

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

C все еще имеет этот дефект сегодня, даже в самом последнем стандарте C.

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