Поделиться через


Строковые и символьные литералы (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
}

Строковые литералы могут быть без префикса, или с префиксами u8, L, 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'.

  • Типовые символьные литералы UTF-16, например char16_t, u'a'

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

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

Кодировка

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

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

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

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

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

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

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

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

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

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

Шестнадцатеричная управляющая последовательность начинается с обратной косой черты, затем следует символ 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 — это массив типа const char[n], с префиксом u8, ограниченный двойными кавычками и оканчивающийся на null, где 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"s создает std::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 до версии 17.0 в 2022: максимальная длина строкового литерала после объединения составляет 65 535 байт. Это относится как к узким, так и к широким строковым литералам.
  • Начиная с Visual Studio 2022 версии 17.0, максимальная длина строкового литерала после объединения ограничена только доступной памятью. Однако ограничение размера до объединения по-прежнему составляет 16 384 байта

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

Так как строковые литералы (не включая 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

Вы можете заставить компилятор выдавать ошибку, когда строковый литерал преобразуется в указатель на неконстантный символ, установив параметр компилятора (отключить преобразование строкового литерала). Мы рекомендуем использовать его для переносимого кода, соответствующего стандартам. Рекомендуется также использовать ключевое слово 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::u8string, std::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-)";

См. также

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