字符串字面量
就地构造一个指定字符数组类型的无名对象,用于将字符串嵌入源代码中。
目录 |
[编辑] 语法
" 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'}
字符串字面量可用于初始化数组,如果数组的大小比字符串字面量的大小小一,则空终止符将被忽略。
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 字符串字面量 (p: 待定)
- C17 标准 (ISO/IEC 9899:2018)
- 6.4.5 字符串字面量 (p: 50-52)
- C11 标准 (ISO/IEC 9899:2011)
- 6.4.5 字符串字面量 (p: 70-72)
- C99 标准 (ISO/IEC 9899:1999)
- 6.4.5 字符串字面量 (p: 62-63)
- C89/C90 标准 (ISO/IEC 9899:1990)
- 3.1.4 字符串字面量
[编辑] 另请参阅
C++ 文档,关于字符串字面量
|