Какой тип строковых литералов в C и C ++? - PullRequest
60 голосов
/ 11 февраля 2010

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

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

Ответы [ 4 ]

59 голосов
/ 11 февраля 2010

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

10 голосов
/ 11 февраля 2010

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

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

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

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

1 голос
/ 26 апреля 2016

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

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

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

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

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

0 голосов
/ 11 февраля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...