Строковые и символьные литералы (C++)

В C++ поддерживаются различные типы строк и символов, а также доступны различные способы выражения значений литералов каждого из этих типов. В исходном коде содержимое символьных и строковых литералов выражается с помощью кодировки. Универсальные имена символов и escape-символы позволяют представить любую строку, используя только основную кодировку исходного кода. Необработанные строковые литералы позволяют не использовать escape-символы и могут применяться для выражения всех типов строковых литералов. Вы также можете создавать std::string литералы, не выполняя дополнительные действия по созданию или преобразованию.

#include <string>
using namespace std::string_literals; // enables s-suffix for std::string literals

int main()
{
    // Character literals
    auto c0 =   'A'; // char
    auto c1 = u8'A'; // char
    auto c2 =  L'A'; // wchar_t
    auto c3 =  u'A'; // char16_t
    auto c4 =  U'A'; // char32_t

    // Multicharacter literals
    auto m0 = 'abcd'; // int, value 0x61626364

    // String literals
    auto s0 =   "hello"; // const char*
    auto s1 = u8"hello"; // const char* before C++20, encoded as UTF-8,
                         // const char8_t* in C++20
    auto s2 =  L"hello"; // const wchar_t*
    auto s3 =  u"hello"; // const char16_t*, encoded as UTF-16
    auto s4 =  U"hello"; // const char32_t*, encoded as UTF-32

    // Raw string literals containing unescaped \ and "
    auto R0 =   R"("Hello \ world")"; // const char*
    auto R1 = u8R"("Hello \ world")"; // const char* before C++20, encoded as UTF-8,
                                      // const char8_t* in C++20
    auto R2 =  LR"("Hello \ world")"; // const wchar_t*
    auto R3 =  uR"("Hello \ world")"; // const char16_t*, encoded as UTF-16
    auto R4 =  UR"("Hello \ world")"; // const char32_t*, encoded as UTF-32

    // Combining string literals with standard s-suffix
    auto S0 =   "hello"s; // std::string
    auto S1 = u8"hello"s; // std::string before C++20, std::u8string in C++20
    auto S2 =  L"hello"s; // std::wstring
    auto S3 =  u"hello"s; // std::u16string
    auto S4 =  U"hello"s; // std::u32string

    // Combining raw string literals with standard s-suffix
    auto S5 =   R"("Hello \ world")"s; // std::string from a raw const char*
    auto S6 = u8R"("Hello \ world")"s; // std::string from a raw const char* before C++20, encoded as UTF-8,
                                       // std::u8string in C++20
    auto S7 =  LR"("Hello \ world")"s; // std::wstring from a raw const wchar_t*
    auto S8 =  uR"("Hello \ world")"s; // std::u16string from a raw const char16_t*, encoded as UTF-16
    auto S9 =  UR"("Hello \ world")"s; // std::u32string from a raw const char32_t*, encoded as UTF-32
}

Строковые литералы не могут иметь префикс или u8L, uи U префиксы для обозначения узкого символа (однобайтового или многобайтового), UTF-8, широкий символ (UCS-2 или UTF-16), кодировки UTF-16 и UTF-32 соответственно. Необработанный строковый литерал может иметь R, u8Rи LRuRUR префиксы для необработанных эквивалентов этих кодировок. Чтобы создать временные или статические std::string значения, можно использовать строковые литералы или необработанные строковые литералы с суффиксом s . Дополнительные сведения см. в разделе "Строковые литералы " ниже. Дополнительные сведения о базовом наборе исходных символов, универсальных именах символов и использовании символов из расширенных кодовых страниц в исходном коде см. в разделе "Наборы символов".

Символьные литералы

Символьный литерал состоит из символьной константы. Он представлен символом, окруженным одними кавычками. Существует пять типов символьных литерала:

  • Обычные символьные литералы типа char, например 'a'

  • Символьные литералы UTF-8 типа char (char8_t в C++20), например u8'a'

  • Расширенные символьные литералы типа wchar_t, например L'a'.

  • Символьные литералы типа char16_tUTF-16, например u'a'

  • Символьные литералы типа char32_tUTF-32, например U'a'

Символ, используемый для литерала символов, может быть любым символом, за исключением зарезервированных символов обратной косой черты (\), одной кавычки (') или новой строки. Зарезервированные символы можно указывать с помощью escape-последовательности. Символы можно указывать с помощью универсальных имен символов, при условии что тип является достаточно крупным для размещения символа.

Кодировка

Литералы символов кодируются по-разному на основе префикса.

  • Литерал символов без префикса — обычный символьный литерал. Значение обычного символьного литерала, содержащего один символ, escape-последовательность или универсальное имя символа, которое может быть представлено в наборе символов выполнения, имеет значение, равное числовому значению его кодировки в наборе символов выполнения. Обычный литерал символов, содержащий несколько символов, escape-последовательность или универсальное имя символов, является многофакторным литералом. Многофакторный литерал или обычный символьный литерал, который не может быть представлен в наборе символов выполнения, имеет тип int, и его значение определяется реализацией. Сведения о MSVC см. в следующем разделе майкрософт.

  • Символьный литерал, начинающийся с L префикса, — это символьный литерал. Значение символьного литерала, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное числовому значению его кодировки в наборе символов, если литерал символов не имеет представления в наборе расширенных символов выполнения, в этом случае значение определяется реализацией. Значение расширенных символьных литералов, содержащих несколько символов, escape-последовательностей или универсальных имен символов, определяется реализацией. Сведения о MSVC см. в следующем разделе майкрософт.

  • Символьный литерал, начинающийся с u8 префикса, — это символьный литерал UTF-8. Значение символьного литерала UTF-8, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное значению точки кода ISO 10646, если оно может быть представлено одним блоком кода UTF-8 (соответствующим блоку элементов управления C0 и Basic Latin Юникод). Если значение не может быть представлено одним блоком кода UTF-8, программа не сформирована. Символьный литерал UTF-8, содержащий несколько символов, escape-последовательность или универсальное имя символов, является неправильно сформированным.

  • Символьный литерал, начинающийся с u префикса, является литералом символов UTF-16. Значение символьного литерала UTF-16, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное значению точки кода ISO 10646, если оно может быть представлено одной единицей кода UTF-16 (соответствующей базовой многоязычной плоскости). Если значение не может быть представлено одним блоком кода UTF-16, программа не сформирована. Литерал символа UTF-16, содержащий несколько символов, escape-последовательность или универсальное имя символов, является неправильно сформированным.

  • Символьный литерал, начинающийся с U префикса, — это символьный литерал UTF-32. Значение символьного литерала UTF-32, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное значению точки кода ISO 10646. Символьный литерал UTF-32, содержащий несколько символов, escape-последовательность или универсальное имя символов, является неправильно сформированным.

Escape-последовательности

Существует три вида escape-последовательностей: простая, восьмеричная и шестнадцатеричная. Escape-последовательности могут быть любым из следующих значений:

Значение escape-последовательность
новая строка \n
обратная косая черта \\
горизонтальная табуляция \t
вопросительный знак ? Или\?
вертикальная табуляция \v
одинарная кавычка \'
BACKSPACE \b
двойная кавычка \"
Возврат каретки \r
нуль-символ \0
Смена страницы \f
восьмеричный \ooo
оповещение (колокольчик) \a
шестнадцатеричный \xhhh

Восьмеричная escape-последовательность — это обратная косая черта, за которой следует последовательность из одной до трех восьмеричных цифр. Восьмеричная escape-последовательность завершается на первом символе, который не является восьмеричной цифрой, если обнаружена раньше, чем третья цифра. Максимально возможное восьмеричное значение .\377

Шестнадцатеричная escape-последовательность — это обратная косая черта, за которой следует символ x, за которой следует последовательность одной или нескольких шестнадцатеричных цифр. Начальные нули пропускаются. В обычном или префиксном литерале символов u8 самое высокое шестнадцатеричное значение 0xFF. В расширенном символьном литерале с префиксом L или u максимальное шестнадцатеричное значение — 0xFFFF. В расширенном символьном литерале с префиксом U максимальное шестнадцатеричное значение — 0xFFFFFFFF.

В этом примере кода показаны некоторые примеры экранированных символов с помощью обычных литералов символов. Тот же синтаксис escape-последовательности действителен для других типов литеральных символов.

#include <iostream>
using namespace std;

int main() {
    char newline = '\n';
    char tab = '\t';
    char backspace = '\b';
    char backslash = '\\';
    char nullChar = '\0';

    cout << "Newline character: " << newline << "ending" << endl;
    cout << "Tab character: " << tab << "ending" << endl;
    cout << "Backspace character: " << backspace << "ending" << endl;
    cout << "Backslash character: " << backslash << "ending" << endl;
    cout << "Null character: " << nullChar << "ending" << endl;
}
/* Output:
Newline character:
ending
Tab character:  ending
Backspace character:ending
Backslash character: \ending
Null character:  ending
*/

Символ обратной косой черты (\) — это символ продолжения строки, когда он помещается в конце строки. Если символ обратной косой черты требуется использовать как символьный литерал, необходимо ввести две косые черты подряд (\\). Дополнительные сведения о символе продолжения строки см. в разделе Phases of Translation.

Только для систем Майкрософт

Чтобы создать значение из узкого многофакторного литерала, компилятор преобразует последовательность символов или символов между одними кавычками в 8-разрядные значения в 32-разрядное целое число. Несколько символов в литерале заполняют соответствующие байты по мере необходимости от высокого до низкого порядка. Затем компилятор преобразует целое число в тип назначения, следуя обычным правилам. Например, чтобы создать char значение, компилятор принимает байт низкого порядка. Для создания значения wchar_t или char16_t компилятор принимает младшее слово. Компилятор выдает предупреждение о том, что результат усекается, если какие-либо биты заданы выше назначенного байта или слова.

char c0    = 'abcd';    // C4305, C4309, truncates to 'd'
wchar_t w0 = 'abcd';    // C4305, C4309, truncates to '\x6364'
int i0     = 'abcd';    // 0x61626364

Восьмеричная escape-последовательность, которая, как представляется, содержит более трех цифр, рассматривается как 3-разрядная октальная последовательность, за которой следует последующие цифры в виде символов в многофакторном литерале, что может дать удивительные результаты. Например:

char c1 = '\100';   // '@'
char c2 = '\1000';  // C4305, C4309, truncates to '0'

Escape-последовательности, которые, как представляется, содержат неосьмеривые символы, оцениваются как восьмеричное последовательность до последнего октационного символа, а затем остальные символы в виде последующих символов в многохарактерном литерале. Предупреждение C4125 создается, если первый не восьмеричный символ является десятичной цифрой. Например:

char c3 = '\009';   // '9'
char c4 = '\089';   // C4305, C4309, truncates to '9'
char c5 = '\qrs';   // C4129, C4305, C4309, truncates to 's'

Восьмеричная escape-последовательность, которая имеет более высокое значение, чем \377 вызывает ошибку C2022: value-in-decimal: слишком большой для символа.

Последовательность escape,которая, как представляется, имеет шестнадцатеричные и не шестнадцатеричные символы, оценивается как многофакторный литерал, содержащий шестнадцатеричную последовательность escape-последовательности до последнего шестнадцатеричного символа, за которым следует не шестнадцатеричные символы. Шестнадцатеричная escape-последовательность, содержащая шестнадцатеричные цифры, приводит к ошибке компилятора C2153: "шестнадцатеричные литералы должны иметь по крайней мере одну шестнадцатеричную цифру".

char c6 = '\x0050'; // 'P'
char c7 = '\x0pqr'; // C4305, C4309, truncates to 'r'

Если расширенный символьный литерал, префиксированный с L несколькими диаграммами, то значение берется из первого символа, а компилятор вызывает предупреждение C4066. Последующие символы игнорируются, в отличие от поведения эквивалентного обычного многофакторного литерала.

wchar_t w1 = L'\100';   // L'@'
wchar_t w2 = L'\1000';  // C4066 L'@', 0 ignored
wchar_t w3 = L'\009';   // C4066 L'\0', 9 ignored
wchar_t w4 = L'\089';   // C4066 L'\0', 89 ignored
wchar_t w5 = L'\qrs';   // C4129, C4066 L'q' escape, rs ignored
wchar_t w6 = L'\x0050'; // L'P'
wchar_t w7 = L'\x0pqr'; // C4066 L'\0', pqr ignored

Раздел , посвященный майкрософт , заканчивается здесь.

универсальные имена символов

В символьных литералах и машинных (не являющихся необработанными) строковых литералах любой символ может быть представлен универсальным именем символа. Универсальные имена символов формируются префиксом \U , за которым следует восьмизначная кодовая точка Юникода или префикс \u , за которым следует четырехзначная точка кода Юникода. Все восемь или четыре знака, соответственно, должны присутствовать для создания корректного универсального имени символа.

char u1 = 'A';          // 'A'
char u2 = '\101';       // octal, 'A'
char u3 = '\x41';       // hexadecimal, 'A'
char u4 = '\u0041';     // \u UCN 'A'
char u5 = '\U00000041'; // \U UCN 'A'

Суррогатные пары

Универсальные имена символов не могут кодировать значения в диапазоне суррогатных точек кода D800-DFFF. Для суррогатных пар Юникода укажите универсальное имя символа, используя \UNNNNNNNN, где NNNNNNNN — восьмизначная кодовая точка для символа. При необходимости компилятор создает суррогатную пару.

В C++03 язык допускает только подмножество символов, представленных их универсальными именами символов, и допускает некоторые универсальные имена символов, которые фактически не представляют допустимые символы Юникода. Эта ошибка была исправлена в стандарте C++11. В C++11 в символьных и строковых литералах и идентификаторах можно использовать универсальные имена символов. Дополнительные сведения об универсальных именах символов см. в разделе Character Sets. Дополнительные сведения о Юникоде см. в статье Unicode. Дополнительные сведения о суррогатных парах см. в статье Surrogate Pairs and Supplementary Characters(Суррогатные пары и дополнительные символы).

Строковые литералы

Строковый литерал представляет последовательность символов, которые вместе образуют строку с завершающим нулем. Символы должны быть заключены в двойные кавычки. Существуют следующие типы строковых литералов.

Узкие строковые литералы

Узкий строковый литерал — это не префиксированный, разделенный двойными кавычками массив const char[n]типа, в котором n — длина массива в байтах. Обычный строковый литерал может содержать любые графические символы, за исключением двойных кавычек ("), обратной косой черты (\) или символа новой строки. Обычный строковый литерал также может содержать перечисленные выше escape-последовательности и универсальные имена символов, которые помещаются в байте.

const char *narrow = "abcd";

// represents the string: yes\no
const char *escaped = "yes\\no";

Строки в кодировке UTF-8

Строка в кодировке UTF-8 — это префиксированный, разделенный двойным кавычками массив типа, завершаемый значением NULL, где n — длина закодированного массива const char[n]в байтах. Строковый литерал с префиксом u8 может содержать любые графические символы, за исключением двойных кавычек ("), обратной косой черты (\) или символа новой строки. Строковый литерал с префиксом u8 может также содержать перечисленные выше escape-последовательности и любые универсальные имена символов.

C++20 представляет переносимый char8_t (UTF-8 закодированный 8-разрядный тип символа Юникода). В C++20 u8 префиксы литералов указывают символы или строки char8_t вместо char.

// Before C++20
const char* str1 = u8"Hello World";
const char* str2 = u8"\U0001F607 is O:-)";
// C++20 and later
const char8_t* u8str1 = u8"Hello World";
const char8_t* u8str2 = u8"\U0001F607 is O:-)";

Расширенные строковые литералы

Широкий строковый литерал — это массив констант wchar_t , префиксируемый символом null, который префиксируется "L" и содержит любой графический символ, кроме двойной кавычки ("), обратной косой черты (\) или символа новой строки. Расширенный строковый литерал может содержать перечисленные выше escape-последовательности и любые универсальные имена символов.

const wchar_t* wide = L"zyxw";
const wchar_t* newline = L"hello\ngoodbye";

char16_t и char32_t (C++11)

В C++11 доступны символьные типы char16_t (портативный, 16-разрядный Юникод) и char32_t (32-разрядный Юникод):

auto s3 = u"hello"; // const char16_t*
auto s4 = U"hello"; // const char32_t*

Необработанные строковые литералы (C++11)

Необработанный строковый литерал — это массив, завершающий значение NULL, любой тип символа, который содержит любой графический символ, включая двойную кавычку (), обратную косую черту ("\) или новый символ. Необработанные строковые литералы часто применяются в регулярных выражениях, которые используют классы символов, а также в строках 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)";
const wchar_t*  raw_wide  = LR"(An unescaped \ character)";
const char*     raw_utf8a = u8R"(An unescaped \ character)"; // Before C++20
const char8_t*  raw_utf8b = u8R"(An unescaped \ character)"; // C++20
const char16_t* raw_utf16 = uR"(An unescaped \ character)";
const char32_t* raw_utf32 = UR"(An unescaped \ character)";

Разделитель — это определяемая пользователем последовательность до 16 символов, которая непосредственно предшествует открытию круглых скобок необработанного строкового литерала и сразу же следует за закрывающей скобкой. Например, в R"abc(Hello"\()abc" последовательность разделителей — abc , а содержимое строки — Hello"\(. Разделители можно использовать для различения необработанных строк, содержащих двойные кавычки и круглые скобки. Этот строковый литерал вызывает ошибку компилятора:

// meant to represent the string: )"
const char* bad_parens = R"()")";  // error C2059

Однако ошибку можно устранить с помощью разделителя:

const char* good_parens = R"xyz()")xyz";

Вы можете создать необработанный строковый литерал, содержащий новую строку (а не экранированный символ) в источнике:

// represents the string: hello
//goodbye
const wchar_t* newline = LR"(hello
goodbye)";

std::string литералы (C++14)

std::string литералы — это стандартные реализации определяемых пользователем литералы (см. ниже), представленные как "xyz"s (суффиксом s ). Такой строковый литерал создает временный объект типа std::string, std::wstringstd::u32stringили std::u16stringв зависимости от указанного префикса. Если префикс не используется, как описано выше, создается.std::string L"xyz"sstd::wstringсоздает объект . u"xyz"sсоздает std::u16string и U"xyz"s создает std::u32string.

//#include <string>
//using namespace std::string_literals;
string str{ "hello"s };
string str2{ u8"Hello World" };     // Before C++20
u8string u8str2{ u8"Hello World" }; // C++20
wstring str3{ L"hello"s };
u16string str4{ u"hello"s };
u32string str5{ U"hello"s };

Суффикс s можно также использовать в необработанных строковых литералах:

u32string str6{ UR"(She said "hello.")"s };

std::string литералы определяются в пространстве std::literals::string_literals имен в файле заголовка <строки> . Поскольку std::literals::string_literalsи std::literals объявляются как встроенные пространства имен, std::literals::string_literals автоматически считается напрямую принадлежащим пространству имен std.

Размер строковых литерала

Для строк ANSI char* и других однобайтовых кодировок (но не UTF-8), размер (в байтах) строкового литерала — это число символов плюс 1 для завершающего символа NULL. Для всех других типов строк размер не связан строго с количеством символов. UTF-8 использует до четырех char элементов для кодирования некоторых единиц кода и char16_twchar_t в кодировке UTF-16 может использовать два элемента (в общей сложности четыре байта) для кодирования одной единицы кода. В примере ниже показан размер расширенного строкового литерала в байтах.

const wchar_t* str = L"Hello!";
const size_t byteSize = (wcslen(str) + 1) * sizeof(wchar_t);

Обратите внимание, что strlen() и wcslen() не включайте размер завершающего символа NULL, размер которого равен размеру элемента типа строки: один байт в char* строке или char8_t* строке, два байта wchar_t* или char16_t* строки и четыре байта в char32_t* строках.

В версиях Visual Studio до Visual Studio 2022 версии 17.0 максимальная длина строкового литерала составляет 65 535 байт. Это ограничение применимо как к узким, так и к расширенным строковым литералам. В Visual Studio 2022 версии 17.0 и более поздних версиях это ограничение будет отменено, а длина строки ограничена доступными ресурсами.

Изменение строковых литерала

Так как строковые литералы (не включая std::string литералы) являются константами, пытаясь изменить их( например, str[2] = 'A'вызывает ошибку компилятора.

Только для систем Майкрософт

В Microsoft C++можно использовать строковый литерал для инициализации указателя на неконст char или wchar_t. Эта неконстантная инициализация разрешена в коде C99, но устарела в C++98 и удалена в C++11. Попытка изменить строку вызовет нарушение прав доступа, как показано в следующем примере:

wchar_t* str = L"hello";
str[2] = L'a'; // run-time error: access violation

Компилятор может вызвать ошибку при преобразовании строкового литерала в указатель неконстного символа при настройке /Zc:strictStrings параметра компилятора (отключить преобразование строковых литеральных типов). Мы рекомендуем использовать его для переносимого кода, соответствующего стандартам. Кроме того, рекомендуется использовать auto ключевое слово для объявления строковых инициализированных указателей, так как он разрешает правильный (const) тип. В следующем примере кода перехватывается во время компиляции попытка записать в строковый литерал:

auto str = L"hello";
str[2] = L'a'; // C3892: 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. Чтобы получить правильный результат, можно использовать одну из следующих escape-последовательностей:

"\005five"     // Use octal literal.
"\x05" "five"  // Use string splicing.

std::stringлитералы (и связанные std::u8stringstd::u16string, иstd::u32string) можно объединить с оператором+, определенным для basic_string типов. Эти литералы также можно соединить аналогично смежным строковым литералам. В обоих случаях кодировка строки и суффикс должны совпадать:

auto x1 = "hello" " " " world"; // OK
auto x2 = U"hello" " " L"world"; // C2308: disagree on prefix
auto x3 = u8"hello" " "s u8"world"z; // C3688, disagree on suffixes

Строковые литералы с универсальными именами символов

Машинные (не являющиеся необработанными) строковые литералы могут использовать универсальные имена символов для представления любого символа, при условии что универсальные имена можно кодировать как один или несколько символов в строковом типе. Например, универсальное имя символа, представляющее расширенный символ, не может быть закодировано в узкой строке с помощью кодовой страницы ANSI, но его можно закодировать в узких строках в некоторых многобайтовых кодовых страницах или в строках UTF-8 или в широкой строке. В C++11 поддержка Юникода расширяется типами char16_t* строк, char32_t* а C++20 расширяет его до char8_t типа:

// ASCII smiling face
const char*     s1 = ":-)";

// UTF-16 (on Windows) encoded WINKING FACE (U+1F609)
const wchar_t*  s2 = L"😉 = \U0001F609 is ;-)";

// UTF-8  encoded SMILING FACE WITH HALO (U+1F607)
const char*     s3a = u8"😇 = \U0001F607 is O:-)"; // Before C++20
const char8_t*  s3b = u8"😇 = \U0001F607 is O:-)"; // C++20

// UTF-16 encoded SMILING FACE WITH OPEN MOUTH (U+1F603)
const char16_t* s4 = u"😃 = \U0001F603 is :-D";

// UTF-32 encoded SMILING FACE WITH SUNGLASSES (U+1F60E)
const char32_t* s5 = U"😎 = \U0001F60E is B-)";

См. также

Наборы символов
Числовые, логические и указательные литералы
Определяемые пользователем литералы