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

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

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

4 ответа

Решение

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

C до сих пор имеет этот недостаток, даже в самом последнем стандарте C.

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

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

Другие вопросы по тегам