字符串字面量
语法
" s字符序列 (可选)"
|
(1) | ||||||||
R" d字符序列 (可选)( r字符序列 (可选)) d字符序列 (可选)"
|
(2) | (C++11 起) | |||||||
L" s字符序列 (可选)"
|
(3) | ||||||||
LR" d字符序列 (可选)( r字符序列 (可选)) d字符序列 (可选)"
|
(4) | (C++11 起) | |||||||
u8" s字符序列 (可选)"
|
(5) | (C++11 起) | |||||||
u8R" d字符序列 (可选)( r字符序列 (可选)) d字符序列 (可选)"
|
(6) | (C++11 起) | |||||||
u" s字符序列 (可选)"
|
(7) | (C++11 起) | |||||||
uR" d字符序列 (可选)( r字符序列 (可选)) d字符序列 (可选)"
|
(8) | (C++11 起) | |||||||
U" s字符序列 (可选)"
|
(9) | (C++11 起) | |||||||
UR" d字符序列 (可选)( r字符序列 (可选)) d字符序列 (可选)"
|
(10) | (C++11 起) | |||||||
解释
s字符序列 | - | 一个或多个s字符 |
s字符 | - | 下列之一: |
基本s字符 | - | 翻译字符集中的字符,不包括双引号(" )、反斜杠(\ )和换行符
|
d字符序列 | - | 一个或多个d字符,最多十六个 |
d字符 | - | 基本字符集中的字符,不包括括号、反斜杠和空格 |
r字符序列 | - | 一个或多个r字符,不得包含闭序列 ) d字符序列"
|
r字符 | - | 翻译字符集中的字符 |
语法 | 种类 | 类型 | 编码 | ||||
---|---|---|---|---|---|---|---|
(1,2) | 普通字符串字面量 | const char[N] | 普通字面量编码 | ||||
(3,4) | 宽字符串字面量 | const wchar_t[N] | 宽字面量编码 | ||||
(5,6) | UTF-8 字符串字面量 |
|
UTF-8 | ||||
(7,8) | UTF-16 字符串字面量 | const char16_t[N] | UTF-16 | ||||
(9,10) | UTF-32 字符串字面量 | const char32_t[N] | UTF-32 |
在上方表格列出的类型中,N 是编码后的代码单元的个数,通过以下方法确定。
普通和 UTF-8 (C++11 起)字符串字面量被统称为窄字符串字面量。
对字符串字面量求值会得到一个具有静态存储期的字符串字面量对象。未指定各字符串字面量是否会存储到不重叠的对象,以及连续求值相同的字符串字面量是否会产生不同的对象。
试图修改字符串字面量对象的效果未定义。
bool b = "bar" == 3 + "foobar"; // 可以是 true 或 false,未指定 const char* pc = "Hello"; char* p = const_cast<char*>(pc); p[0] = 'M'; // 行为未定义
原始字符串字面量原始字符串字面量是前缀包含 // OK:包含一个反斜杠,等价于 "\\" R"(\)"; // OK:包含四个 \n 字符对,等价于 "\\n\\n\\n\\n" R"(\n\n\n\n)"; // OK:包含一个右括号、两个双引号和一个左括号,等价于 ")\"\"(" R"-()""()-"; // OK:等价于 "\n)\\\na\"\"\n" R"a( )\ a"" )a"; // OK:等价于 "x = \"\"\\y\"\"" R"(x = ""\y"")"; // R"<<(-_-)>>"; // 错误:两端的分隔序列不匹配 // R"-()-"-()-"; // 错误:)-" 在中间出现,导致字面量终止 |
(C++11 起) |
初始化
字符串字面量对象会以与该字面量的s字符 和r字符 (C++11 起)序列对应的代码单元值序列,加上一个终止空字符(U+0000),按以下顺序初始化:
T
为该字符串字面量的数组元素类型(见上表):
- 如果 v 在
T
的表示范围内,那么该转义序列对应一个值为 v 的代码单元。 - 否则,如果该字符串字面量具有语法 (1) 或 (3),并且 (C++11 起) v 在
T
的底层类型对应的无符号整数类型的表示范围内,那么该转义序列对应一个代码单元,带代码单元具有一个T
类型的与 v mod 2S
同余的值,其中 S 是T
的宽度。 - 否则程序非良构。
拼接
在翻译阶段 6(预处理后),相邻的字符串字面量会被拼接起来:
- 如果两个字符串的种类相同,那么拼接后的字符串字面量也具有该种类。
|
(C++11 前) | ||||
|
(C++11 起) |
"Hello, " " world!" // 在阶段 6,这两个字符串字面量会组成 "Hello, world!" L"Δx = %" PRId16 // 在阶段 4,PRId16 展开成 "d" // 在阶段 6,L"Δx = %" 与 "d" 组成 L"Δx = %d"
- ↑ 没有支持这种拼接的已知实现。
不求值字符串
以下语境需要字符串字面量,但不会对它求值:
- 语言链接说明
(C++11 起) | |
|
(C++14 起) |
|
(C++20 起) |
(C++26 起) |
除了字面量运算符名(只能使用普通字符串字面量)以外, (C++11 起)标准没有指定这些语境下是否允许使用普通字符串字面量以外的字符串字面量。实现的行为不一致。 |
(C++26 前) |
这些语境下只能使用普通字符串字面量。 不求值字符串中的每个通用字符名和简单转义序列都会被它表示的翻译字符集成员替代。包含数值转义序列或条件转义序列的不求值字符串非良构。 |
(C++26 起) |
注解
字符串字面量可用于初始化字符数组。如果数组初始化类似 char str[] = "foo";,那么 str 将含有字符串 "foo" 的副本。
字符串字面量可以转换到且可以赋给非 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) (DR20) |
兼容 char8_t 并修复可移植性(允许从 UTF-8 字符串字面量初始化(unsigned)char 数组) |
__cpp_raw_strings |
200710L | (C++11) | 原始字符串字面量 |
__cpp_unicode_literals |
200710L | (C++11) | Unicode 字符串字面量 |
示例
#include <iostream> // array1 和 array2 包含相同的值: 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 411 (P2029R4) |
C++98 | 字符串字面量中的转义序列不能对应多个代码单元 | 可以对应 |
CWG 1656 (P2029R4) |
C++98 | 字符串字面量中的数值转义序列对应的字符不明确 | 使之明确 |
CWG 1759 | C++11 | UTF-8 字符串字面量可能会有 char 无法表示的编码单元 | char 可以表示所有 UTF-8 编码单元 |
CWG 1823 | C++98 | 字符串字面量是否有别由实现定义 | 区别性未指明,相同字符串字面量能产生不同对象 |
CWG 2333 (P2029R4) |
C++11 | 不明确 UTF-8/16/32 字符串字面量 是否可以包含数值转义序列 |
使之明确 |
CWG 2870 | C++11 | 两个普通字符串字面量的拼接结果不明确 | 使之明确 |
P1854R4 | C++23 | 包含不可编码字符的通常或宽字符串字面量受条件性支持 | 包含此类字面量的程序非良构 |
P2029R4 | C++98 | 1. 不明确字符串字面量是否可以包含不可编码字符 2. 不明确字符串字面量是否可以包含表示的代码单元 无法以字面量的数组元素类型表示的数值转义序列 |
1. 包含它们的通常或宽字符串字面量受条件性支持[1] 2. 在底层类型对应的无符号整数类型 也无法表示的情况下程序非良构 |
- ↑ 后续 P1854R4 被接受为缺陷报告,覆盖了此修改方案。
引用
- C++23 标准(ISO/IEC 14882:2024):
- 5.13.5 String literals [lex.string]
- C++20 标准(ISO/IEC 14882:2020):
- 5.13.5 String literals [lex.string]
- C++17 标准(ISO/IEC 14882:2017):
- 5.13.5 String literals [lex.string]
- C++14 标准(ISO/IEC 14882:2014):
- 2.14.5 String literals [lex.string]
- C++11 标准(ISO/IEC 14882:2011):
- 2.14.5 String literals [lex.string]
- C++03 标准(ISO/IEC 14882:2003):
- 2.13.4 String literals [lex.string]
- C++98 标准(ISO/IEC 14882:1998):
- 2.13.4 String literals [lex.string]
参阅
用户定义字面量(C++11) | 拥有用户定义后缀的字面量 |