Строковые литералы в C++
Строковый литерал представляет последовательность символов, которые вместе образуют строку с завершающим нулем. Символы должны быть заключены в двойные кавычки. Существуют следующие типы строковых литералов.
Узкие строковые литералы, представленные как "xxx".
Расширенные строковые литералы, представленные как L"xxx".
Необработанные строковые литералы, представленные как R"ddd(xxx) ddd", где ddd — разделитель. Необработанные строковые литералы могут быть либо узкими (представленными с помощью R) или расширенными (представленными с помощью LR).
Узкий строковый литерал — это завершающийся нулем массив констант char, который может содержать любые графические символы, за исключением двойных кавычек ("), обратной косой черты (\) или символа новой строки. Узкий строковый литерал может содержать escape-последовательности, перечисленные в разделе Знаковые литералы C++.
const char *narrow = "abcd";
// represents the string: yes\no
const char *escaped = "yes\\no";
Расширенный строковый литерал — это завершающийся нулем массив констант wchar_t, который может содержать любые графические символы, за исключением двойных кавычек ("), обратной косой черты (\) или символа новой строки. Расширенный строковый литерал может содержать escape-последовательности, перечисленные в разделе Знаковые литералы C++.
const wchar_t* wide = L"zyxw";
const wchar_t* newline = L"hello\ngoodbye";
Необработанный строковый литерал — это завершающийся нулевым значением массив констант типа char или wchar_t, который может содержать любые графические символы, включая двойные кавычки ("), обратную косую черту (\) и символ новой строки. Необработанные строковые литералы часто применяются в регулярных выражениях, которые используют классы символов, а также в строках HTML и XML. Примеры см. в следующей статье: Bjarne Stroustrup's FAQ on C++11 (Вопросы и ответы о C++11 от Бьярна Страуструпа).
// represents the string: An unescaped \ character
const char* raw_narrow = R"(An unescaped \ character)";
// represents the string: An unescaped " character
const wchar_t* raw_wide = LR"(An unescaped " character)";
Разделитель — это содержащая до 16 символов пользовательская последовательность, которая стоит непосредственно перед открывающей круглой скобкой и сразу после закрывающей круглой скобки необработанного строкового литерала. Разделители можно использовать для различения строк, содержащих двойные кавычки и круглые скобки. Следующая строка приводит к ошибке компилятора:
// meant to represent the string: )”
const char* bad_parens = R"()")";
Однако ошибку можно устранить с помощью разделителя:
const char* good_parens = R"xyz()")xyz";
Можно создать необработанный строковый литерал, содержащий символ новой строки (не escape-символ) в исходном коде:
// represents the string: hello
//goodbye
const wchar_t* newline = LR"(hello
goodbye)";
Размер строковых литералов
Размер узкого строкового литерала (в байтах) равен количеству символов плюс 1 (для завершающего нуль-символа); размер расширенного строкового литерала (в байтах) равен удвоенному числу символов плюс 2 (для завершающего нуль-символа). Ниже представлен размер расширенного строкового литерала.
const wchar_t* str = L"Hello!";
const size_t byteSize = (wcslen(str) + 1) * sizeof(wchar_t);
Обратите внимание, что значения strlen() и wcslen() не включают размер завершающего нуль-символа.
Максимальная длина строкового литерала — 65535 байт. Это ограничение применимо как к узким, так и к расширенным строковым литералам.
Изменение строковых литералов
Строковые литералы — это константы, поэтому любая попытка изменить их — как, например в строке str[2] = "A" — приведет к ошибке компилятора.
Блок, относящийся только к системам Microsoft
В Visual C++ строковый литерал можно использовать для инициализации указателя не являющимся константным значением типа char или wchar_t. Это разрешено в коде C, но не рекомендуется в С++98 и удалено из С++11. Попытка изменить строку вызовет нарушение прав доступа, как показано в следующем примере:
wchar_t* str = L"hello";
str[2] = L'a'; // run-time error: access violation
Чтобы указать компилятору выдавать ошибку при преобразовании строкового литерала в символ non_const, можно задать компилятора /Zc:strictStrings (отключение преобразования типов строковых литералов). Рекомендуется объявлять инициализируемые строковым литералом указатели с помощью ключевого слова auto. Таким образом происходит преобразование в правильный тип (const). В следующем примере перехватывается попытка записать строковый литерал во время компиляции:
auto str = L"hello";
str[2] = L'a'; // Compiler error: you cannot assign to a variable that is const
В некоторых случаях идентичные строковые литералы могут быть объединены в пул для экономии места в исполняемом файле. При объединении строковых литералов в пулы компилятор делает так, что все ссылки на определенный строковый литерал указывают на одну и ту же область в памяти, вместо того чтобы каждая ссылка указывала на отдельный экземпляр строкового литерала. Для включения объединения строковых литералов в пулы используется параметр компилятора /GF.
Завершение блока, относящегося только к системам Майкрософт
Сцепление смежных строковых литералов
Смежные строковые литералы сцепляются. Данное объявление:
char str[] = "12" "34";
идентично следующему объявлению:
char atr[] = "1234";
и следующему объявлению:
char atr[] = "12\
34";
Использование встроенных шестнадцатеричных escape-кодов для задания строковых констант может приводить к непредвиденным результатам. В следующем примере выполняется попытка создать строковый литерал, содержащий символ ASCII 5, за которым следуют символы f, i, v и e:
"\x05five"
Фактический результат (шестнадцатеричное значение 5F) является кодом ASCII для символа подчеркивания, за которым следуют символы i, v и e. Чтобы получить правильный результат, можно воспользоваться одним из следующих способов:
"\005five" // Use octal constant.
"\x05" "five" // Use string splicing.
Строковые литералы с символами Юникода
Суррогатные пары и дополнительные символы (как в UTF-16) представляются с помощью префикса \U. Это расширенные строки, а не отдельные символы, они представлены двойными кавычками, а не одинарными. Префиксы U, u и u8 не поддерживаются.
const wchar_t* str1 = L"\U0002008A";
const wchar_t* str2 = L"\UD869DED6";
const wchar_t* str3 = L"\Udc00c800";
Дополнительные сведения о Юникоде см. здесь). Дополнительные сведения о суррогатных парах см. в статье Surrogate Pairs and Supplementary Characters (Суррогатные пары и дополнительные символы).