常量

常量是具有固定值的表达式。

文字

文字是最明显的常量类型。它们用于表达程序源代码中的特定值。我们已经在前面的章节中,使用过一些为变量赋予特定值或表达我们希望程序打印出来的消息,例如,当我们编写时:

1
a = 5;

这段代码中的 5 是一个文字常量。

文字常量可分为:整型、浮点型、字符型、字符串型、布尔型、指针型和用户定义型常量。

整型常量

1
2
3
1776
707
-

这些是标识整数值的整型常量。请注意,它们没有用引号或任何其他特殊字符括起来;它们是代表十进制整数的简单数字序列;例如, 1776 始终表示值 1776。

除了十进制数(我们大多数人每天都使用的十进制数)之外,C++ 还允许使用八进制数(以 8 为基数)和十六进制数(以 16 为基数)作为整型常量。对于八进制文字,数字前面带有 0 (零)字符。对于十六进制,它们前面带有字符 0x (零、x)。例如,以下整型常量彼此等效:

1
2
3
75         // decimal
0113 // octal
0x4b // hexadecimal

所有这些都代表相同的数字:75(七十五)分别表示为以 10 为基数的数字、八进制数字和十六进制数字。

这些整型常量有一个类型,就像变量一样。默认情况下,整型常量的类型为 int 。但是,某些后缀可以附加到整数文字上以指定不同的整数类型:

后缀 类型修饰符
u 或 U unsigned
l 或 L long
ll 或 LL long long

Unsigned 可以以任意顺序与其他两个中的任何一个组合形成 unsigned long 或 unsigned long long 。

例如:

1
2
3
4
5
75         // int
75u // unsigned int
75l // long
75ul // unsigned long
75lu // unsigned long

在上述所有情况下,可以使用大写或小写字母指定后缀。

浮点数常量
它们用小数或指数表示实数值。它们可以包含小数点、 e 字符(表示“第 X 高度处的十”,其中 X 是紧随 e 字符的整数值),或两者都包含小数点和 e 字符:

1
2
3
4
3.14159    // 3.14159
6.02e23 // 6.02 x 10^23
1.6e-19 // 1.6 x 10^-19
3.0 // 3.0

这是用 C++ 表示的四个带小数的有效数字。第一个数字是 PI,第二个是阿伏伽德罗数,第三个是电子的电荷(一个极小的数字)——所有这些都是近似值——最后一个是用浮点数表示的数字 3。

浮点数的默认类型是 double 。可以通过添加以下后缀之一来指定 float 或 long double 类型的浮点数:

后缀 类型
f 或 F float
l 或 L long double

例如:

1
2
3.14159L   // long double
6.02e23f // float

可以作为浮点数值常量一部分的任何字母( e 、 f 、 l )都可以使用小写或大写字母编写意义没有区别。

字符和字符串常量
字符和字符串常量用引号引起来:

1
2
3
4
'z'
'p'
"Hello world"
"How do you do?"

前两个表达式表示字符常量,后面两个表示由多个字符组成的字符串常量。请注意,要表示单个字符,我们将其括在单引号 ( ‘ ) 之间,而要表示字符串(通常由多个字符组成),我们将字符括在双引号 ( “ )。

字符和字符串常量都需要用引号将它们括起来,以将它们与可能的变量标识符或保留关键字区分开。注意这两个表达式之间的区别:

1
2
x
'x'

这里, x 单独引用一个标识符,例如变量的名称或复合类型,而 ‘x’ (用单引号括起来)将引用字符常量(代表小写 x 字母的字符)。

字符和字符串常量还可以表示在程序源代码中很难或不可能表达的特殊字符,例如换行符 ( \n ) 或制表符 ( \t )。这些特殊字符前面都有一个反斜杠字符 ( \ )。

这里有单字符转义码的列表:

转义码 描述
\n 换行
\r 回车
\t tab
\v 垂直制表符
\b 退格键
\f 换页
\a 警报(蜂鸣声)
\’ 单引号 ( ‘ )
\” 双引号( “ )
\? 问号( ? )
\ \ 反斜杠( \ )

例如:

1
2
3
4
'\n'
'\t'
"Left \t Right"
"one\ntwo\nthree"

在内部,计算机将字符表示为数字码:最典型的是,它们使用 ASCII 字符编码系统的一种扩展(有关详细信息,请参阅 ASCII 代码)。字符还可以使用其数字码以文字形式表示,方法是编写反斜杠字符 ( \ ),后跟表示为八进制 (base-8) 或十六进制 (base-16) 数字的代码。对于八进制值,反斜杠后面直接跟数字;而对于十六进制,则在反斜杠和十六进制数字本身之间插入 x 字符(例如: \x20 或 \x4A )。

只需用一个或多个空格(包括制表符、换行符和其他有效空白字符)分隔即可将多个字符串连接起来形成单个字符串。例如:

1
2
"this forms" "a single"     " string "
"of characters"

上面是一个字符串,相当于:

1
"this formsa single string of characters"

请注意引号内的空格是文字的一部分,而引号外的空格则不是。

一些程序员还使用一种技巧在多行中包含长字符串文字:在 C++ 中,行末尾的反斜杠 ( \ ) 被视为行继续字符,该字符将该行和下一行合并到一行。因此以下代码:

1
2
x = "string expressed in \
two lines"

相当于:
1
x = "string expressed in two lines"

上述所有字符和字符串均由 char 类型的字符组成。可以使用以下前缀之一指定不同的字符类型:

前缀 字符类型
u char16_t
U char32_t
L wchar_t

请注意,与整数的类型后缀不同,这些前缀区分大小写:小写表示 char16_t ,大写表示 char32_t 和 wchar_t 。

对于字符串,除了上面的 u 、 U 和 L 之外,还存在两个附加前缀:

前缀 描述
u8 字符串使用 UTF-8 编码在可执行文件中
R 字符串是原始字符串

在原始字符串中,反斜杠、单引号和双引号都是有效字符;文字的内容由初始 R”sequence( 和最终 )sequence” 分隔,其中 sequence 是任何字符序列(包括空序列)。字符串的内容是括号内的内容,忽略分隔序列本身。例如:

1
2
R"(string with \backslash)"
R"&%$(string with \backslash)&%$"

上面的两个字符串都相当于 “string with \ \backslash” 。 R 前缀可以与任何其他前缀组合,例如 u 、 L 或 u8 。

其他常量
C++ 中存在三个关键字文字: true 、 false 和 nullptr :
true 和 false 是 bool 类型变量的两个可能值。
nullptr 是空指针值。

1
2
3
bool foo = true;
bool bar = false;
int* p = nullptr;

类型化常量表达式

有时,为常量值命名很方便:

1
const char tab = '\t';

然后我们可以使用这些名称而不是它们定义的常量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

const double pi = 3.14159;
const char newline = '\n';

int main ()
{
double r=5.0; // radius
double circle;

circle = 2 * pi * r;
cout << circle;
cout << newline;
}

编辑和在线运行

预处理器定义 (#define)

命名常量值的另一种机制是使用预处理器定义。它们具有以下形式:

1
#define identifier replacement

在此指令之后,代码中出现的任何 identifier 都会被解释替换为 replacement 。这种替换由预处理器执行,并且发生在程序编译之前,然而也可能会导致某种盲目替换:不进行任何方式检查所涉及的类型或语法的有效性。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

#define PI 3.14159
#define NEWLINE '\n'

int main ()
{
double r=5.0; // radius
double circle;

circle = 2 * PI * r;
cout << circle;
cout << NEWLINE;

}

编辑和在线运行

请注意, #define 行是预处理器指令,因此是单行指令,与 C++ 语句不同,末尾不需要分号 (;);该指令自动延伸到该行的末尾。如果该行中包含分号,则它是替换的一部分,并且也包含在所有被替换的位置中。