Namespaces
Variants

String literals

From cppreference.net

Создает неименованный объект указанного типа массива символов на месте, используется, когда строку символов необходимо встроить в исходный код.

Содержание

Синтаксис

" s-char-sequence " (1)
u8" s-char-sequence " (2) (начиная с C11)
u" s-char-sequence " (3) (начиная с C11)
U" s-char-sequence " (4) (начиная с C11)
L" s-char-sequence " (5)

где

s-char-sequence - ноль или более символов, каждый из которых является либо многобайтовым символом из исходного набора символов (исключая ( " ), \ , и перевод строки), либо escape-последовательностью символа, шестнадцатеричной escape-последовательностью, восьмеричной escape-последовательностью , или универсальным именем символа (начиная с C99) , как определено в escape-последовательностях .
1) строковый литерал символов : Тип литерала char [ N ] , где N - размер строки в кодовых единицах узкой кодировки выполнения, включая нулевой терминатор. Каждый char элемент в массиве инициализируется из следующего символа в s-char-sequence с использованием набора символов выполнения.
2) Строковый литерал UTF-8 : Тип литерала char [ N ] (до C23) char8_t [ N ] (начиная с C23) , где N - размер строки в кодовых единицах UTF-8 включая нулевой терминатор. Каждый char (до C23) char8_t (начиная с C23) элемент в массиве инициализируется из следующего многобайтового символа в s-char-sequence с использованием кодировки UTF-8.
3) Строковый литерал 16-битной ширины: Тип литерала - char16_t [ N ] , где N - размер строки в кодовых единицах реализации 16-битной кодировки (обычно UTF-16), включая нулевой терминатор. Каждый элемент char16_t в массиве инициализируется как если бы выполнялась функция mbrtoc16 в реализации локали.
4) Строковый литерал 32-битной ширины: Тип литерала - char32_t [ N ] , где N - размер строки в кодовых единицах реализации 32-битной кодировки (обычно UTF-32), включая нулевой терминатор. Каждый элемент char32_t в массиве инициализируется как если бы выполнялась функция mbrtoc32 в реализации локали.
(до C23)
3) UTF-16 строковый литерал : Тип литерала - char16_t [ N ] , где N - размер строки в UTF-16 кодовых единицах, включая нулевой терминатор. Каждый элемент char16_t в массиве инициализируется из следующего многобайтового символа в s-char-sequence с использованием UTF-16 кодировки.
4) UTF-32 строковый литерал : Тип литерала - char32_t [ N ] , где N - размер строки в UTF-32 кодовых единицах, включая нулевой терминатор. Каждый элемент char32_t в массиве инициализируется из следующего многобайтового символа в s-char-sequence с использованием UTF-32 кодировки.
(начиная с C23)
5) широкий строковый литерал: Тип литерала wchar_t [ N ] , где N — размер строки в кодовых единицах широкой кодировки выполнения, включая нулевой терминатор. Каждый wchar_t элемент в массиве инициализируется как если бы выполнялся вызов mbstowcs в реализации-определенной локали.

Объяснение

Сначала, на фазе трансляции 6 (после раскрытия макросов), смежные строковые литералы (то есть строковые литералы, разделённые только пробельными символами) объединяются.

Только два узких или два широких строковых литерала могут быть объединены.

(until C99)

Если один литерал не имеет префикса, результирующий строковый литерал имеет ширину/кодировку, указанную префиксированным литералом.

L"Δx = %" PRId16 // at phase 4, PRId16 expands to "d"
                 // at phase 6, L"Δx = %" and "d" form L"Δx = %d"
(since C99)

Если два строковых литерала имеют разные префиксы кодировки, конкатенация определяется реализацией, за исключением того, что строковый литерал UTF-8 и широкий строковый литерал не могут быть конкатенированы.

(начиная с C11)
(до C23)

Если два строковых литерала имеют разные префиксы кодировки, конкатенация является некорректной.

(начиная с C23)

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

char* p = "\x12" "3"; // создает статический массив char[3], содержащий {'\x12', '3', '\0'}
                      // устанавливает p на указатель первого элемента массива

Строковые литералы неизменяемы (и фактически могут размещаться в памяти только для чтения, такой как .rodata ). Если программа пытается изменить статический массив, сформированный строковым литералом, поведение не определено.

char* p = "Hello";
p[1] = 'M'; // Неопределённое поведение
char a[] = "Hello";
a[1] = 'M'; // OK: a не является строковым литералом

Не требуется и не запрещается, чтобы идентичные строковые литералы ссылались на одну и ту же область памяти. Более того, перекрывающиеся строковые литералы или строковые литералы, являющиеся подстроками других строковых литералов, могут быть объединены.

"def" == 3+"abcdef"; // может быть 1 или 0, зависит от реализации

Примечания

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

char* p = "abc\0def"; // strlen(p) == 3, но массив имеет размер 8

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

//char* p = "\xfff"; // ошибка: шестнадцатеричная escape-последовательность вне диапазона
char* p = "\xff""f"; // корректно, литерал имеет тип char[3] содержащий {'\xff', 'f', '\0'}

Строковые литералы могут использоваться для инициализации массивов , и если размер массива на единицу меньше размера строкового литерала, нулевой терминатор игнорируется:

char a1[] = "abc"; // a1 — это char[4] содержит {'a', 'b', 'c', '\0'}
char a2[4] = "abc"; // a2 — это char[4] содержит {'a', 'b', 'c', '\0'}
char a3[3] = "abc"; // a3 — это char[3] содержит {'a', 'b', 'c'}

Кодировка строковых литералов символов (1) и широких строковых литералов (5) определяется реализацией. Например, gcc выбирает их с помощью командных опций - fexec - charset и - fwide - exec - charset .

Хотя смешанная конкатенация широких строковых литералов разрешена в C11, почти все компиляторы отвергают такую конкатенацию (единственное известное исключение - SDCC ), и опыт её использования неизвестен. В результате разрешение смешанной конкатенации широких строковых литералов удалено в C23.

Пример

#include <inttypes.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <uchar.h>
int main(void)
{
    char s1[] = "a猫🍌"; // or "a\u732B\U0001F34C"
#if __STDC_VERSION__ >= 202311L
    char8_t
#else
    char
#endif
    s2[] = u8"a猫🍌";
    char16_t s3[] = u"a猫🍌";
    char32_t s4[] = U"a猫🍌";
    wchar_t s5[] = L"a猫🍌";
    setlocale(LC_ALL, "en_US.utf8");
    printf("  \"%s\" is a char[%zu] holding     { ", s1, sizeof s1 / sizeof *s1);
    for(size_t n = 0; n < sizeof s1 / sizeof *s1; ++n)
        printf("0x%02X ", +(unsigned char)s1[n]);
    puts("}");
    printf(
#if __STDC_VERSION__ >= 202311L
    "u8\"%s\" is a char8_t[%zu] holding  { "
#else
    "u8\"%s\" is a char[%zu] holding     { "
#endif
, s2, sizeof s2 / sizeof *s2);
    for(size_t n = 0; n < sizeof s2 / sizeof *s2; ++n)
#if __STDC_VERSION__ >= 202311L
       printf("0x%02X ", s2[n]);
#else
       printf("0x%02X ", +(unsigned char)s2[n]);
#endif
    puts("}");
    printf(" u\"a猫🍌\" is a char16_t[%zu] holding { ", sizeof s3 / sizeof *s3);
    for(size_t n = 0; n < sizeof s3 / sizeof *s3; ++n)
       printf("0x%04" PRIXLEAST16" ", s3[n]);
    puts("}");
    printf(" U\"a猫🍌\" is a char32_t[%zu] holding { ", sizeof s4 / sizeof *s4);
    for(size_t n = 0; n < sizeof s4 / sizeof *s4; ++n)
       printf("0x%08" PRIXLEAST32" ", s4[n]);
    puts("}");
    printf(" L\"%ls\" is a wchar_t[%zu] holding  { ", s5, sizeof s5 / sizeof *s5);
    for(size_t n = 0; n < sizeof s5 / sizeof *s5; ++n)
       printf("0x%08X ", (unsigned)s5[n]);
    puts("}");
}

Возможный вывод:

  "a猫🍌" is a char[9] holding     { 0x61 0xE7 0x8C 0xAB 0xF0 0x9F 0x8D 0x8C 0x00 }
u8"a猫🍌" is a char[9] holding     { 0x61 0xE7 0x8C 0xAB 0xF0 0x9F 0x8D 0x8C 0x00 }
 u"a猫🍌" is a char16_t[5] holding { 0x0061 0x732B 0xD83C 0xDF4C 0x0000 }
 U"a猫🍌" is a char32_t[4] holding { 0x00000061 0x0000732B 0x0001F34C 0x00000000 }
 L"a猫🍌" is a wchar_t[4] holding  { 0x00000061 0x0000732B 0x0001F34C 0x00000000 }

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2024):
  • 6.4.5 Строковые литералы (стр: TBD)
  • Стандарт C17 (ISO/IEC 9899:2018):
  • 6.4.5 Строковые литералы (стр: 50-52)
  • Стандарт C11 (ISO/IEC 9899:2011):
  • 6.4.5 Строковые литералы (стр: 70-72)
  • Стандарт C99 (ISO/IEC 9899:1999):
  • 6.4.5 Строковые литералы (стр: 62-63)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
  • 3.1.4 Строковые литералы

Смотрите также

C++ documentation для string literal