String literal
目录 |
语法
"
s-char-seq
(可选)
"
|
(1) | ||||||||
R"
d-char-seq
(可选)
(
r-char-seq
(可选)
)
d-char-seq
(可选)
"
|
(2) | (自 C++11 起) | |||||||
L"
s-char-seq
(可选)
"
|
(3) | ||||||||
LR"
d-char-seq
(可选)
(
r-char-seq
(可选)
)
d-char-seq
(可选)
"
|
(4) | (自 C++11 起) | |||||||
u8"
s-char-seq
(可选)
"
|
(5) | (自 C++11 起) | |||||||
u8R"
d-char-seq
(可选)
(
r-char-seq
(可选)
)
d-char-seq
(可选)
"
|
(6) | (自 C++11 起) | |||||||
u"
s-char-seq
(可选)
"
|
(7) | (自 C++11 起) | |||||||
uR"
d-char-seq
(可选)
(
r-char-seq
(可选)
)
d-char-seq
(可选)
"
|
(8) | (自 C++11 起) | |||||||
U"
s-char-seq
(可选)
"
|
(9) | (自 C++11 起) | |||||||
UR"
d-char-seq
(可选)
(
r-char-seq
(可选)
)
d-char-seq
(可选)
"
|
(10) | (自 C++11 起) | |||||||
说明
| s-char-seq | - | 一个或多个 s-char 的序列 |
| s-char | - | 以下之一 |
| basic-s-char | - | 来自 基本源字符集 (C++23前) 翻译字符集 (C++23起) 的字符,但不包括双引号 " 、反斜杠 \ 或换行符 |
| d-char-seq | - | 一个或多个 d-char 的序列,长度最多16个字符 |
| d-char | - | 来自 基本源字符集 (C++23前) 基本字符集 (C++23起) 的字符,但不包括圆括号、反斜杠和 空白字符 |
| r-char-seq | - |
一个或多个
r-char
的序列,但不能包含结束序列
)
d-char-seq
"
|
| r-char | - | 来自 基本源字符集 (C++23前) 翻译字符集 (C++23起) 的字符 |
| 语法 | 种类 | 类型 | 编码 | ||||
|---|---|---|---|---|---|---|---|
| (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 (since 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"-()-"-()-"; // 错误:)-" 出现在中间并终止了字面量 |
(since C++11) |
初始化
字符串字面量对象按照以下顺序,使用对应字符串字面量中 s-char 序列 和 r-char 序列 (C++11 起) 的代码单元值序列进行初始化,并附加终止空字符 (U+0000):
T
为字符串字面量的数组元素类型(参见
上表
):
-
若
v
未超过
T的可表示值范围,则转义序列贡献一个值为 v 的单个代码单元。 -
否则,若
字符串字面量采用语法
(1)
或
(3)
,且
(C++11 起)
v
未超过
T底层类型对应无符号类型的可表示值范围,则转义序列贡献一个T类型的唯一值代码单元,该值同余于 v mod 2 S
,其中 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"; // 正确:该字面量为 const char[3] 类型,包含 {'\xff','f','\0'}
| 功能测试 宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_char8_t
|
202207L
|
(C++23)
(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"; // 正确,等同于 const wchar_t* s5 = L"ABCDEF"; const char32_t* s6 = U"GHI" "JKL"; // 正确,等同于 const char32_t* s7 = U"GHIJKL"; const char16_t* s9 = "MN" u"OP" "QR"; // 正确,等同于 const char16_t* sA = u"MNOPQR"; // const auto* sB = u"Mixed" U"Types"; // C++23 之前可能由实现支持也可能不支持; // 自 C++23 起格式错误 const wchar_t* sC = LR"--(STUV)--"; // 正确,原始字符串字面量 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++98 |
包含不可编码字符的普通和宽字符
字符串字面量是条件性支持的 |
包含此类字面量的程序非良构 |
| P2029R4 | C++98 |
1. 字符串字面量是否可包含
不可编码字符不明确 2. 字符串字面量是否可包含 数值转义序列,使得其表示的 代码单元无法在字面量的 数组元素类型中表示不明确 |
1. 对普通和宽字符串字面量
改为条件性支持 [1] 2. 若代码单元既无法在底层类型 对应的无符号整数类型中表示, 则非良构 |
- ↑ P1854R4 后来被接受为缺陷报告,推翻了此项决议。
参考文献
- C++23 标准 (ISO/IEC 14882:2024):
-
- 5.13.5 字符串字面量 [lex.string]
- C++20 标准 (ISO/IEC 14882:2020):
-
- 5.13.5 字符串字面量 [lex.string]
- C++17 标准 (ISO/IEC 14882:2017):
-
- 5.13.5 字符串字面量 [lex.string]
- C++14 标准 (ISO/IEC 14882:2014):
-
- 2.14.5 字符串字面量 [lex.string]
- C++11 标准 (ISO/IEC 14882:2011):
-
- 2.14.5 字符串字面量 [lex.string]
- C++03 标准 (ISO/IEC 14882:2003):
-
- 2.13.4 字符串字面量 [lex.string]
- C++98 标准 (ISO/IEC 14882:1998):
-
- 2.13.4 字符串字面量 [lex.string]
参阅
| 用户定义字面量 (C++11) | 带有用户定义后缀的字面量 |
|
C 文档
关于
字符串字面量
|
|