字符串字面量
语法
" s字符序列(可选)"
|
(1) | ||||||||
L" s字符序列(可选)"
|
(2) | ||||||||
u8" s字符序列(可选)"
|
(3) | (C++11 起) | |||||||
u" s字符序列(可选)"
|
(4) | (C++11 起) | |||||||
U" s字符序列(可选)"
|
(5) | (C++11 起) | |||||||
前缀(可选) R" d字符序列(可选)( r字符序列(可选)) d字符序列(可选)"
|
(6) | (C++11 起) | |||||||
解释
s字符序列 | - | 一个或多个s字符 |
s字符 | - | 下列之一: |
基础s字符 | - | 来自源字符集 (C++23 前)翻译字符集 (C++23 起)去掉双引号(" )、反斜杠(\ )和换行符后的字符
|
前缀 | - | L 、u8 、u 、U 之一
|
d字符序列 | - | 一个或多个d字符,最多十六个 |
d字符 | - | 来自基础源字符集 (C++23 前)基础字符集 (C++23 起)去掉括号、反斜杠和空格后的字符 |
r字符序列 | - | 一个或多个r字符,不得包含闭序列 ) d字符序列"
|
r字符 | - | 来自源字符集 (C++23 前)翻译字符集 (C++23 起)的字符 |
N
是以执行窄编码 (C++23 前)通常字面量编码 (C++23 起)的编码单元计的字符串的大小,包含空终止符。N
是以执行宽编码 (C++23 前)宽字面量编码 (C++23 起)的编码单元计的字符串的大小,包含空终止符。N
是以 UTF-8 编码单元计的字符串的大小,包含空终止符。N
是以 UTF-16 编码单元计的字符串的大小,包含空终止符。N
是以 UTF-32 编码单元计的字符串的大小,包含空终止符。每个(来自非原始字符串字面量的)s字符 或(来自原始字符串字面量的)r字符 (C++11 起)均初始化字符串字面量对象中的对应元素。一个 s字符 或 r字符 (C++11 起)当且仅当它被字符串字面量的关联字符编码中多于一个编码单元的序列表示时对应多于一个元素。
如果字符缺少在关联字符编码中的表示,
|
(C++23 起) |
每个数值转义序列对应单个元素。如果转义序列所指定的值适合元素类型的无符号版本,则元素拥有(可能在转换到元素类型后的)指定值;否则(即指定值在范围外)该字符串字面量非良构。 (C++23 起)
拼接
在翻译阶段 6(预处理器之后),毗邻的字符串字面量会被拼接起来。即 "Hello," " world!" 生成(单个)字符串 "Hello, world!"。如果两个字符串的编码前缀相同(或者都没有编码前缀),则产生的字符串将拥有相同的编码前缀(或无前缀)。
如果一个字符串有编码前缀而另一个没有,则无编码前缀者被认为拥有与另一者相同的编码前缀。 L"Δx = %" PRId16 // 在阶段 4,PRId16 展开成 "d" // 在阶段 6,L"Δx = %" 与 "d" 组成 L"Δx = %d" 如果 UTF-8 字符串字面量与宽字符串字面量毗邻,则程序非良构。 |
(C++11 起) |
实现可能支持或不支持任何其他编码前缀组合。这种拼接的结果是实现定义的。 |
(C++11 起) (C++23 前) |
任何其他编码前缀组合为非良构。 |
(C++23 起) |
注解
字符串字面量始终要追加空字符('\0'、L'\0'、char16_t() 等):因此,字符串字面量 "Hello" 是 const char[6],并保有字符 'H'、'e'、'l'、'l'、'o' 及 '\0'。
通常字符串字面量 (1) 和宽字符串字面量 (2) 的编码是实现定义的。例如,gcc 用命令行选项 -fexec-charset 与 -fwide-exec-charset 选择它们。
字符串字面量拥有静态存储期,从而在程序生存期间存在于内存中。
字符串字面量可用于初始化字符数组。如果数组初始化类似 char str[] = "foo";,那么 str 将含有字符串 "foo" 的副本。
字符串字面量能否重叠以及同一字符串字面量的相继求值是否产生同一对象是未指明的。这意味着以指针比较时,相同的字符串字面量比较时可能相等或不相等。
bool b = "bar" == 3+"foobar" // 可为 true 或 false,由实现定义
试图修改字符串字面量导致未定义行为:它们可以存储于只读存储(例如 .rodata
)或与其他字符串字面量合并:
const char* pc = "Hello"; char* p = const_cast<char*>(pc); p[0] = 'M'; // 未定义行为
字符串字面量可转换为且可赋值给非 const 的 char* 或 wchar_t* 以与 C 兼容, C 中字符串字面量类型为 char[N] 与 wchar_t[N]。 这种隐式转换被弃用。 |
(C++11 前) |
字符串字面量不可转换为或赋值给非 const 的 CharT*。若想要这种转换则必须用显式转型(例如 |
(C++11 起) |
字符串字面量不需要是一个空终止字符序列:如果字符串字面量包含内嵌的空字符,那么它表示含有多于一条字符串的数组。
const char* p = "abc\0def"; // std::strlen(p) == 3 ,但数组大小为 8
如果字符串字面量中一个十六进制转义后随一个合法十六进制数位,则可能因非法转义序列而编译失败。此时可以拼接字符串:
//const char* p = "\xfff"; // 错误:十六进制转义序列在范围外 const char* p = "\xff""f"; // OK :此字面量是保有 {'\xff','f','\0'} 的 const char[3]
尽管 C++11 中允许混合的宽字符串字面量连接,所有已知的 C++ 编译器都拒绝这种连接,而其使用经验是未知的。结果 C++23 中移除了对混合宽字符串字面量连接的允许。
示例
#include <iostream> char array1[] = "Foo" "bar"; // 同 char array2[] = { 'F', 'o', 'o', 'b', 'a', 'r', '\0' }; const char* s1 = R"foo( Hello World )foo"; // 同 const char* s2 = "\nHello\n World\n"; // 同 const char* s3 = "\n" "Hello\n" " World\n"; int main() { std::cout << array1 << '\n'; std::cout << array2 << '\n'; std::cout << s1 << s2 << s3; }
输出:
Foobar Foobar Hello World Hello World Hello World
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
DR | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 1823 | C++98 | 字符串字面量是否有别是实现定义的 | 区别性未指明,相同字符串字面量能产生不同对象 |
参阅
用户定义字面量(C++11) | 拥有用户定义后缀的字面量 |