6.4.4 常量
TIP
这一节的重点不只是“字面量长什么样”,而是“它的类型怎样确定”。很多表达式在一开始就已经因为常量类型不同而埋下了后续转换差异。
6.4.4.1 一般规定
常量分为以下几类:
- 整数常量;
- 浮点常量;
- 枚举常量;
- 字符常量;
- 预定义常量。
每个常量都必须具有类型,并且它的值必须落在该类型可表示值的范围内。
常量的类型由其书写形式和值共同决定,具体规则见下面各小节。
6.4.4.2 整数常量
整数常量以数字开头,不含小数点,也不含指数部分。它可以带:
- 前缀,用来指定进制;
- 后缀,用来指定类型。
整数常量与浮点常量中可选出现的单引号
'叫做数字分隔符。它在求值时会被忽略。支持的书写形式包括:
- 十进制:以非零数字开头;
- 八进制:以
0开头,后续只能是0到7; - 十六进制:以
0x或0X开头; - 二进制:以
0b或0B开头。
各种进制的值分别按基数
10、8、16、2计算,最左边的数字是最高位。
常见后缀
| 后缀 | 含义 |
|---|---|
| 无后缀 | 在标准给定候选类型表中,取第一个能表示该值的类型 |
u / U | 倾向无符号整数类型 |
l / L | 倾向 long 系列 |
ll / LL | 倾向 long long |
wb / WB | 产生位精确整数类型 _BitInt(N) |
u + wb | 产生 unsigned _BitInt(N) |
- 无后缀十进制整数常量的候选顺序是:
int -> long int -> long long int- 无后缀八进制、十六进制、二进制整数常量的候选顺序是:
int -> unsigned int -> long int -> unsigned long int
-> long long int -> unsigned long long int2
其他带后缀形式,也都遵循“在该后缀对应的候选列表中,选择第一个能表示该值的类型”的原则。
对
wb/WB后缀:3wb产生某个最小宽度的_BitInt(N),该宽度必须既能表示数值,也要包含符号位;3uwb产生某个最小宽度的unsigned _BitInt(N),该宽度只需容纳该值。
如果某个不带
wb/WB/uwb/UWB后缀的整数常量,无法由其候选表中的任何标准类型表示,则它可以使用扩展整数类型;若仍无可表示的扩展整数类型,则该整数常量没有类型。
数字分隔符示例
0b11'10'11'01 /* 等价于 0b11101101 */
'1'2 /* 是字符常量 '1' 再跟整数常量 2,不是整数常量 12 */
11'22 /* 等价于 1122 */
0x'FFFF'FFFF /* 非法:' 不能紧跟在 0x 后 */
0x1'2'3'4AB'C'D /* 等价于 0x1234ABCD */2
3
4
5
wb 后缀示例
-3wb /* 先得到 _BitInt(3),再做一元负号 */
-0x3wb /* 同样先得到 _BitInt(3),再做一元负号 */
3wb /* 得到 _BitInt(3) */
3uwb /* 得到 unsigned _BitInt(2) */
-3uwb /* 先得到 unsigned _BitInt(2),再做算术求负,发生回绕 */2
3
4
5
IMPORTANT
常量本身不带符号。-3 不是“带负号的整数常量”,而是“一元 - 作用于整数常量 3”。
6.4.4.3 浮点常量
浮点常量分为两类:
- 十进制浮点常量;
- 十六进制浮点常量。
浮点常量由三部分组成:
- 有效数字部分(significand);
- 可选的指数部分;
- 可选的后缀。
十进制浮点常量的指数部分用
e或E;十六进制浮点常量的二进制指数部分用p或P。对十进制浮点常量,必须至少出现小数点或指数部分中的一个。
后缀与类型的对应关系如下:
| 后缀 | 类型 |
|---|---|
| 无后缀 | double |
f / F | float |
l / L | long double |
df / DF | _Decimal32 |
dd / DD | _Decimal64 |
dl / DL | _Decimal128 |
df、dd、dl及其大写形式不能用于十六进制浮点常量。十进制浮点常量的指数表示对
10的幂缩放;十六进制浮点常量的指数表示对2的幂缩放。当
FLT_RADIX是2的幂时,十六进制浮点常量会被正确舍入;其他情形下,结果可能是最近可表示值,或与最近值相邻的上/下一个可表示值,具体由实现定义。浮点常量的值可以在比其语义类型要求更大的范围和精度中表示,但这不会改变其类型。
十进制浮点常量中,即使两个常量的数值相同,只要量子指数不同,其内部表示仍然可以不同。
浮点常量在翻译期就会转换为内部格式;这种转换不应在执行期引发浮点异常。
NOTE
十六进制浮点常量是表达“精确二进制浮点值”的重要工具。很多需要避免十进制舍入误差的场景,更适合直接写成十六进制浮点形式。
阅读提示:负号与舍入
标准特别提醒:浮点常量本身不包含符号。像 -1.0 这样的写法,含义是“先形成常量 1.0,再对它做一元负号”。因此,“先舍入后取负”和“先把负号并入输入再转换”在某些舍入方向下可能得到不同结果。
6.4.4.4 枚举常量
枚举常量在词法上就是一个标识符。
对没有固定底层类型的枚举,其枚举常量的类型是
int或该枚举类型,具体见6.7.3.3。对具有固定底层类型的枚举,其枚举常量具有对应的枚举类型。
枚举常量可以在任何允许使用整数类型值的表达式或常量表达式中使用。
6.4.4.5 字符常量
字符常量写在单引号中。根据前缀不同,可分为:
- 普通整数字符常量:无前缀,如
'x'; - UTF-8 字符常量:
u8'x'; wchar_t字符常量:L'x';- UTF-16 字符常量:
u'x'; - UTF-32 字符常量:
U'x'。
- 普通整数字符常量:无前缀,如
其中
L、u、U这三类统称为宽字符常量。可以使用的转义序列包括:
| 含义 | 写法 |
|---|---|
| 单引号 | \\' |
| 双引号 | \\\" |
| 问号 | \\? |
| 反斜杠 | \\\\ |
| 八进制转义 | \\ 后跟 1 到 3 个八进制数字 |
| 十六进制转义 | \\x 后跟若干十六进制数字 |
| 通用字符名 | \\uXXXX / \\UXXXXXXXX |
八进制和十六进制转义都遵循最长匹配。也就是说,只要后面的字符还能继续构成该转义,它们就会继续被吞进去。
八进制或十六进制转义序列所形成的数值,必须落在对应类型可表示的范围内。对应类型如下:
| 前缀 | 对应类型 |
|---|---|
| 无前缀 | unsigned char |
u8 | char8_t |
L | wchar_t 对应的无符号类型 |
u | char16_t |
U | char32_t |
UTF-8、UTF-16、UTF-32 字符常量都不得包含多于一个字符;并且该值必须能由单个 UTF 代码单元表示。
普通整数字符常量的类型是
int。若其中只有一个字符,并且该字符在字面量编码中映射为单个值,那么它的值就是该编码值再按整数解释后的结果。多字符字符常量,例如
'ab',以及不能映射为单个字面量编码值的字符常量,其值由实现定义。u8字符常量的类型是char8_t;若不是通过八进制或十六进制转义写出的,那么它的值等于对应的 ISO/IEC 10646 码点值,但前提是该码点能编码成单个 UTF-8 代码单元。u字符常量的类型是char16_t,U字符常量的类型是char32_t,L字符常量的类型是wchar_t。它们的值由对应宽字面量编码与类型规则确定。
WARNING
多字符字符常量不是字符串,也不是可移植写法。像 'ab' 这样的写法,其值由实现定义,不应当拿来写可移植代码。