Литералы строк
Создаёт анонимный объект указанного типа массива символов на месте, используется, когда строка символов должна быть встроена в исходный код.
Синтаксис
" Последовательность символов s " | (1) | |
u8" Последовательность символов s " | (2) | (с C11) |
u" Последовательность символов s " | (3) | (с C11) |
U" Последовательность символов s " | (4) | (с C11) |
L" Последовательность символов s " | (5) |
где
| Последовательность символов s | - | ноль или более символов, каждый из которых является многобайтовым символом из набора символов исходного кода (исключая ("), \, и символ новой строки), или escape-последовательность, шестнадцатеричная escape-последовательность, восьмеричная escape-последовательность, или универсальное имя символа(с C99), как определено в escape-последовательностях. |
char[N], где N — размер строки в кодовых единицах выполнения узкой кодировки, включая нулевой терминатор. Каждый элемент char массива инициализируется следующим символом в Последовательности символов s с использованием набора символов выполнения.char[N](до C23)char8_t[N](с C23), где N — размер строки в кодовых единицах UTF-8, включая нулевой терминатор. Каждый элемент char(до C23)char8_t(с C23) массива инициализируется следующим многобайтовым символом в Последовательности символов s с использованием кодировки 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 с использованием кодировки UTF-16. 4) литерал строки UTF-32: Тип литерала — char32_t[N], где N — размер строки в кодовых единицах UTF-32, включая нулевой терминатор. Каждый элемент char32_t массива инициализируется следующим многобайтовым символом в Последовательности символов s с использованием кодировки UTF-32. | (с C23) |
wchar_t[N], где N — размер строки в кодовых единицах выполнения широкой кодировки, включая нулевой терминатор. Каждый элемент wchar_t массива инициализируется, как если бы выполнялось mbstowcs в реализации локали.Объяснение
Во-первых, на стадии трансляции 6 (после подстановки макросов), смежные строковые литералы (то есть строковые литералы, разделённые только пробелами) конкатенируются.
| Можно конкатенировать только два узких или два широких строковых литерала. | (до C99) |
| Если один литерал не имеет префикса, результирующий строковый литерал имеет ширину/кодировку, указанную префиксным литералом. L"Δx = %" PRId16 // at phase 4, PRId16 expands to "d"
// at phase 6, L"Δx = %" and "d" form L"Δx = %d" | (с C99) |
| Если два строковых литерала имеют разные префиксы кодировки, конкатенация определяется реализацией, за исключением того, что строковый литерал UTF-8 и литерал строки с широким символом не могут быть конкатенированы. |
(с C11) (до C23) |
| Если два строковых литерала имеют разные префиксы кодировки, конкатенация является ошибочной. | (с C23) |
Во-вторых, на стадии трансляции 7 к каждому строковому литералу добавляется нулевой терминатор, а затем каждый литерал инициализирует безымянный массив со статическим сроком хранения и размером, достаточным для хранения содержимого строкового литерала плюс один нулевой терминатор.
char* p = "\x12" "3"; // creates a static char[3] array holding {'\x12', '3', '\0'}
// sets p to point to the first element of the arrayСтроковые литералы не могут быть изменены (и, фактически, могут быть размещены в памяти только для чтения, например, .rodata). Если программа пытается изменить статический массив, образованный строковым литералом, поведение не определено.
char* p = "Hello"; p[1] = 'M'; // Undefined behavior char a[] = "Hello"; a[1] = 'M'; // OK: a is not a string literal
Не требуется и не запрещено, чтобы идентичные строковые литералы ссылались на одно и то же место в памяти. Кроме того, перекрывающиеся строковые литералы или строковые литералы, которые являются подстроками других строковых литералов, могут быть объединены.
"def" == 3+"abcdef"; // may be 1 or 0, implementation-defined
Примечания
Строковый литерал не обязательно является строкой; если строковый литерал содержит вложенные нулевые символы, он представляет массив, который содержит более одной строки:
char* p = "abc\0def"; // strlen(p) == 3, but the array has size 8
Если действительный шестнадцатеричный символ следует за шестнадцатеричной escape-последовательностью в строковом литерале, это не скомпилируется в качестве недопустимой escape-последовательности, но конкатенация строк может использоваться в качестве обходного пути:
//char* p = "\xfff"; // error: hex escape sequence out of range
char* p = "\xff""f"; // okay, the literal is char[3] holding {'\xff', 'f', '\0'}Строковые литералы могут использоваться для инициализации массивов, и если размер массива на единицу меньше размера строкового литерала, нулевой терминатор игнорируется:
char a1[] = "abc"; // a1 is char[4] holding {'a', 'b', 'c', '\0'}
char a2[4] = "abc"; // a2 is char[4] holding {'a', 'b', 'c', '\0'}
char a3[3] = "abc"; // a3 is char[3] holding {'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:2023):
- 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++ для литерала строки |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/string_literal