字符字面量

来自cppreference.com
< cpp‎ | language
 
 
 
表达式
概述
值类别(左值 lvalue、右值 rvalue、亡值 xvalue)
求值顺序(序列点)
常量表达式
潜在求值表达式
初等表达式
lambda 表达式(C++11)
字面量
整数字面量
浮点字面量
布尔字面量
字符字面量,包含转义序列
字符串字面量
空指针字面量(C++11)
用户定义字面量(C++11)
运算符
赋值运算符a=ba+=ba-=ba*=ba/=ba%=ba&=ba|=ba^=ba<<=ba>>=b
自增与自减++a--aa++a--
算术运算符+a-aa+ba-ba*ba/ba%b~aa&ba|ba^ba<<ba>>b
逻辑运算符a||ba&&b!a
比较运算符a==ba!=ba<ba>ba<=ba>=ba<=>b(C++20)
成员访问运算符a[b]*a&aa->ba.ba->*ba.*b
其他运算符a(...)a,ba?b:c
new 表达式
delete 表达式
throw 表达式
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
折叠表达式(C++17)
运算符的代用表示
优先级和结合性
运算符重载
默认比较(C++20)
类型转换
隐式转换
一般算术转换
const_cast
static_cast
reinterpret_cast
dynamic_cast
显式转换 (T)a, T(a)
用户定义转换
 

语法

'c字符 ' (1)
u8'c字符 ' (2) (C++17 起)
u'c字符 ' (3) (C++11 起)
U'c字符 ' (4) (C++11 起)
L'c字符 ' (5)
'c字符序列 ' (6)
L'c字符序列 ' (7) (C++23 前)
c字符 - 下列之一:
基本c字符 - 来自基本源字符集 (C++23 前)翻译字符集 (C++23 起)去掉单引号(')、反斜杠(\)和换行符后的字符
c字符序列 - 两个或更多个c字符

解释

1) 通常字符字面量,例如 'a''\n''\13'。这种字面量具有 char 类型,且它的值等于c字符 在执行字符集中的表示 (C++23 前)来自通常字面量编码的对应代码单元 (C++23 起)
2) UTF-8 字符字面量,例如 u8'a'。这种字面量具有 char (C++20 前)char8_t (C++20 起) 类型,且它的值等于c字符 的 ISO/IEC 10646 码位值,只要码位值能以单个 UTF-8 代码单元表示(即c字符 处于范围 0x0-0x7F(含边界)内)。
3) UTF-16 字符字面量,例如 u'猫',但不是 u'🍌'u'\U0001f34c')。这种字面量具有 char16_t 类型,且它的值等于c字符 的 ISO/IEC 10646 码位值,只要该值能以单个 UTF-16 代码单元表示(即c字符 处于范围 0x0-0xFFFF(含边界)内)。
4) UTF-32 字符字面量,例如 U'猫'U'🍌'。这种字面量具有 char32_t 类型,且它的值等于c字符 的 ISO/IEC 10646 码位值。
5) 宽字符字面量,例如 L'β'L'猫'。这种字面量具有 wchar_t 类型,且它的值等于c字符 在执行宽字符集中的表示 (C++23 前)来自宽字面量编码的对应代码单元 (C++23 起)
6) 通常多字符字面量 (C++23 前)多字符字面量 (C++23 起)(条件性支持),例如 'AB',具有 int 类型和实现定义的值。
7) 宽多字符字面量(条件性支持),例如 L'AB',具有 wchar_t 类型和实现定义的值。

不可编码字符

1-5)c字符 不是数值转义序列(见下文)的情况下,如果c字符 无法在字面量对应的编码中表示,或者无法在该编码中表示为单个代码单元(例如在 wchar_t 是 16 位的 Windows 上的非 BMP 值),那么程序非良构。
6) 如果c字符序列 中有任何c字符序列 无法在通常字面量编码中表示为单个代码单元,那么程序非良构。
7) 如果c字符序列 中有任何c字符序列 无法在宽字面量编码中表示为单个代码单元,那么程序非良构。
(C++23 前)

数值转义序列

数值(八进制与十六进制)转义序列能用于指定字符的值。

如果字符字面量只包含一个数值转义序列,且该转义序列指定的值能以它的类型的无符号版本表示,那么字符字面量拥有与指定值(可能在转换到字符类型后)相同的值。

UTF-N 字符字面量能拥有它的类型可表示的任意值。即使该值对应的码位在 Unicode 中不合法或在 UTF-N 中无法以单个代码单元表示,该值的数值转义序列依然可以指定它。例如 u8'\xff' 良构并等于 char8_t(0xFF)

(C++23 起)


如果一个通常或宽字符字面量中用来指定值的数值转义序列指定了一个无法分别以 charwchar_t 表示的值,那么该字符字面量的值由实现定义。

(C++23 前)

如果一个有单个c字符 的通常或宽字符字面量中用来指定值的数值转义序列所指定的值能分别以 charwchar_t 的底层类型的无符号版本表示,那么该字面量的值是转换到字面量类型的有该无符号整数类型与指定值的整数值。否则程序非良构。

(C++23 起)


如果一个 UTF-N 字符字面量中用来指定值的数值转义序列所指定的值不能以对应的 charN_t 表示,那么字符字面量的值由实现定义 (C++17 前)程序非良构 (C++17 起)

(C++11 起)

注解

多字符字面量是 C 从 B 编程语言继承而来的。尽管 C 或 C++ 标准不指定,大多数编译器(值得注意的例外是 MSVC )也如 B 中所指定实现多字符字面量:字面量中的每个字符的值以大端序零填充右对齐顺序初始化结果整数的相继字节,例如 '\1' 的值为 0x00000001'\1\2\3\4' 的值为 0x01020304

在 C 中,诸如 'a''\n' 之类的字符常量具有 int 类型,而不是 char

示例

#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string_view>
 
template<typename CharT>
void dump(std::string_view s, const CharT c)
{
    const uint8_t* data{reinterpret_cast<const uint8_t*>(&c)};
 
    std::cout << "'" << s << "' \t" << std::hex
              << std::uppercase << std::setfill('0');
 
    for (auto i{0U}; i != sizeof(CharT); ++i)
        std::cout << std::setw(2) << static_cast<unsigned>(data[i]) << ' ';
 
    std::cout << '\n';
}
 
void print(std::string_view str) { std::cout << str; }
 
int main()
{
    print("通常字符字面量:");
    char c1 = 'a'; dump("'a'", c1);
    char c2 = '\x2a'; dump("'*'", c2);
 
    print("\n" "通常多字符字面量:");
    int mc1 = 'ab'; dump("'ab'", mc1);       // 由实现定义
    int mc2 = 'abc'; dump("'abc'", mc2);     // 由实现定义
 
    print("\n" "UTF-8 字符字面量:");
    char8_t C1 = u8'a'; dump("u8'a'", C1);
//  char8_t C2 = u8'¢'; dump("u8'¢'", C2);   // 错误:¢ 会映射到两个 UTF-8 代码单元
//  char8_t C3 = u8'猫'; dump("u8'猫'", C3); // 错误:猫 会映射到三个 UTF-8 代码单元
//  char8_t C4 = u8'🍌'; dump("u8'🍌'", C4); // 错误:🍌 会映射到四个 UTF-8 代码单元
 
    print("\n" "UTF-16 字符字面量:");
    char16_t uc1 = u'a'; dump("u'a'", uc1);
    char16_t uc2 = u'¢'; dump("u'¢'", uc2);
    char16_t uc3 = u'猫'; dump("u'猫'", uc3);
//  char16_t uc4 = u'🍌'; dump("u'🍌'", uc4); // 错误:🍌 会映射到两个 UTF-16 代码单元
 
    print("\n" "UTF-32 字符字面量:");
    char32_t Uc1 = U'a'; dump("U'a'", Uc1);
    char32_t Uc2 = U'¢'; dump("U'¢'", Uc2);
    char32_t Uc3 = U'猫'; dump("U'猫'", Uc3);
    char32_t Uc4 = U'🍌'; dump("U'🍌'", Uc4);
 
    print("\n" "宽字符字面量:");
    wchar_t wc1 = L'a'; dump("L'a'", wc1);
    wchar_t wc2 = L'¢'; dump("L'¢'", wc2);
    wchar_t wc3 = L'猫'; dump("L'猫'", wc3);
    wchar_t wc4 = L'🍌'; dump("L'🍌'", wc4);  // 从 C++23 开始在 Windows 上不支持
}

可能的输出:

通常字符字面量:
'a' 	61 
'*' 	2A 
 
通常多字符字面量:
'ab' 	62 61 00 00 
'abc' 	63 62 61 00 
 
UTF-8 字符字面量:
u8'a' 	61 
 
UTF-16 字符字面量:
u'a' 	61 00 
u'¢' 	A2 00 
u'猫' 	2B 73 
 
UTF-32 字符字面量:
U'a' 	61 00 00 00 
U'¢' 	A2 00 00 00 
U'猫' 	2B 73 00 00 
U'🍌' 	4C F3 01 00 
 
宽字符字面量:
L'a' 	61 00 00 00 
L'¢' 	A2 00 00 00 
L'猫' 	2B 73 00 00 
L'🍌' 	4C F3 01 00

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 912 C++98 未指明不可编码的通常字符字面量 指定为条件性支持
CWG 1024 C++98 要求支持多字符字面量 改为条件性支持
CWG 1656 C++98 字符字面量中的数值转义序列的含义不明确 已指定
P1854R4 C++98 包含不可编码字符的字符字面量受条件性支持 程序非良构

参阅

用户定义字面量(C++11) 拥有用户定义后缀的字面量