字符串字面量
语法
" 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 起)的字符 |
每个(来自非原始字符串字面量的)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 起) |
不求值字符串
以下语境需要字符串,但不会对它求值:
- 语言链接说明
-
static_assert
(C++11 起) - 字面量运算符名 (C++11 起)
-
[[deprecated]]
(C++14 起) -
[[nodiscard]]
(C++20 起)
标准没有指定这些语境下是否允许使用编码前缀(除了字面量运算符名不能有编码前缀) (C++11 起)。实现的行为不一致。 |
(C++26 前) |
这些语境下不能使用编码前缀。 不求值字符串中的每个通用字符名和简单转义序列都会被它表示的翻译字符集成员替代。包含数值转义序列或条件转义序列的不求值字符串非良构。 |
(C++26 起) |
注解
字符串字面量始终要追加空字符('\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 的 |
(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]
功能特性测试宏 | 值 | 标准 | 注释 |
---|---|---|---|
__cpp_char8_t |
202207L | (C++20) (DR) |
兼容 char8_t 并修复可移植性(允许从 UTF-8 字符串字面量初始化(unsigned)char 数组) |
__cpp_raw_strings |
200710L | (C++11) | 原始字符串字面量 |
__cpp_unicode_literals |
200710L | (C++11) | Unicode 字符串字面量 |
示例
#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"; const wchar_t* s4 = L"ABC" L"DEF"; // OK,同 const wchar_t* s5 = L"ABCDEF"; const char32_t* s6 = U"GHI" "JKL"; // OK,同 const char32_t* s7 = U"GHIJKL"; const char16_t* s9 = "MN" u"OP" "QR"; // OK,同 const char16_t* sA = u"MNOPQR"; // const auto* sB = u"Mixed" U"Types"; // C++23 前实现可能不支持;C++23 起非良构 const wchar_t* sC = LR"--(STUV)--"; // OK,原始字符串字面量 int main() { std::cout << array1 << ' ' << array2 << '\n' << s1 << s2 << s3 << std::endl; std::wcout << s4 << ' ' << s5 << ' ' << sC << std::endl; }
输出:
Foobar Foobar Hello World Hello World Hello World ABCDEF ABCDEF STUV
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 1759 | C++11 | UTF-8 字符串字面量可能会有 char 无法表示的编码单元 | char 可以表示所有 UTF-8 编码单元 |
CWG 1823 | C++98 | 字符串字面量是否有别是实现定义的 | 区别性未指明,相同字符串字面量能产生不同对象 |
P1854R4 | C++23 | 包含不可编码字符的字符串字面量受条件性支持 | 程序非良构 |
参阅
用户定义字面量(C++11) | 拥有用户定义后缀的字面量 |