字符串字面量
构造一个指定字符数组类型的未命名对象,用于在源代码中嵌入字符串时。
目录 |
[编辑] 语法
" 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 | - | 零个或多个字符,每个字符可以是源字符集中的多字节字符(不包括 (" )、\ 和换行符),或者字符转义符、十六进制转义符、八进制转义符,或通用字符名(自 C99 起),如 转义序列 中定义。 |
N
是字符串在执行窄编码中的代码单元大小,包括空终止符。数组中的每个 char 元素都使用执行字符集从 s-char-sequence 中的下一个字符初始化。N
是字符串在 UTF-8 代码单元中的大小,包括空终止符。数组中的每个 char(直到 C23)char8_t(自 C23 起) 元素都使用 UTF-8 编码从 s-char-sequence 中的下一个多字节字符初始化。
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 元素都使用 UTF-16 编码从 s-char-sequence 中的下一个多字节字符初始化。4) UTF-32 字符串字面量:字面量的类型是 char32_t[N],其中 N 是字符串在 UTF-32 代码单元中的大小,包括空终止符。数组中的每个 char32_t 元素都使用 UTF-32 编码从 s-char-sequence 中的下一个多字节字符初始化。 |
(自 C23 起) |
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
如果有效的十六进制数字跟在字符串字面量中的十六进制转义符之后,则它将无法编译为无效的转义序列,但字符串连接可以用作一种解决方法
//char* p = "\xfff"; // error: hex escape sequence out of range char* p = "\xff""f"; // okay, the literal is char[3] holding {'\xff', 'f', '\0'}
字符串字面量可以用于初始化数组,并且如果数组的大小比字符串字面量的大小小 1,则空终止符将被忽略
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:2024)
- 6.4.5 字符串字面量 (页码:待定)
- 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++ 文档 关于 字符串字面量
|