String literals
Создает неименованный объект указанного типа массива символов на месте, используется, когда строку символов необходимо встроить в исходный код.
Содержание |
Синтаксис
"
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-последовательностях
.
|
N
- размер строки в кодовых единицах узкой кодировки выполнения, включая нулевой терминатор. Каждый
char
элемент в массиве инициализируется из следующего символа в
s-char-sequence
с использованием набора символов выполнения.
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) |
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
|