重要的事情说三遍:
常量是具有固定值的表达式。
字面量(Literals)
字面量是最明显的一种常量。它们用于在程序的源代码中表达特定的值。我们已经在前几章中使用过一些字面量来为变量赋予特定的值或表达我们希望程序打印的消息,例如,当我们写到:
a = 5;
这段代码中的5
就是一个字面量常量。
字面量常量可以分类为:整数、浮点数、字符、字符串、布尔值、指针和用户定义的字面量。
整数字面量(Integer Numerals)
1776
707
-
这些是表示整数值的数值常量。注意它们没有用引号或其他特殊字符括起来;它们是代表十进制整数的一串简单的数字;例如,1776
总是表示值 一千七百七十六 。
除了十进制数(我们日常使用的),C++还允许使用八进制数(以8为基数)和十六进制数(以16为基数)作为字面量常量。对于八进制字面量,数字前加一个0
(零)字符。而对于十六进制字面量,前加字符0x
(零和x)。例如,以下字面量常量都是等价的:
75 // 十进制
0113 // 八进制
0x4b // 十六进制
这些都表示相同的数字:75(七十五),分别以十进制、八进制和十六进制表示。
这些字面量常量和变量一样,有其类型。默认情况下,整数字面量的类型是int
。然而,可以在整数字面量后添加某些后缀以指定不同的整数类型:
后缀 | 类型修饰符 |
---|---|
u 或 U | unsigned (无符号) |
l 或 L | long (长整型) |
ll 或 LL | long long (长长整型) |
无符号修饰符可以与其他两种修饰符任意组合形成unsigned long
或unsigned long long
。
例如:
75 // int
75u // unsigned int
75l // long
75ul // unsigned long
75lu // unsigned long
在上述所有情况下,后缀可以使用大写或小写字母。
浮点数字面量(Floating Point Numerals)
浮点数字面量表达实数值,带有小数和/或指数。它们可以包括小数点、一个e
字符(表示“乘以10的 X 次方”,其中 X 是紧跟在e
字符后的整数值),或者同时包括小数点和e
字符:
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 |
例如:
3.14159L // long double
6.02e23f // float
浮点数字面量中的所有字母(e
、f
、l
)可以用大写或小写字母书写,意义相同。
字符和字符串字面量(Character and string literals)
字符和字符串字面量用引号括起来:
'z'
'p'
"Hello world"
"How do you do?"
前两个表达式表示单字符字面量,后两个表示由多个字符组成的字符串字面量。注意,为了表示单个字符,我们用单引号('
)括起来,而为了表示字符串(通常由多个字符组成),我们用双引号("
)括起来。
单字符和字符串字面量都需要引号将它们与可能的变量标识符或保留关键字区分开来。注意这两个表达式之间的区别:
x 'x'
这里,x
单独使用表示一个标识符,例如变量名或复合类型的名称,而'x'
(用单引号括起来)表示字符字面量'x'
(表示小写字母_x_的字符)。
字符和字符串字面量还可以表示在程序源代码中难以或无法表达的特殊字符,如换行符(\n)或制表符(\t)。这些特殊字符都以反斜杠字符(\ )开头。
以下是单字符转义码的列表:
转义码 | 描述 |
---|---|
\n | 换行 |
\r | 回车 |
\t | 制表符 |
\v | 垂直制表符 |
\b | 退格 |
\f | 换页 |
\a | 响铃(蜂鸣) |
\' | 单引号(' ) |
\" | 双引号(" ) |
\? | 问号(? ) |
\\ | 反斜杠(\ ) |
例如:
'\n'
'\t'
"Left \t Right"
"one\ntwo\nthree"
在内部,计算机将字符表示为数值代码:通常,它们使用ASCII字符编码系统的扩展(参见ASCII码了解更多信息)。字符也可以用其数值代码在字面量中表示,方法是写一个反斜杠字符(\)后跟代码以八进制(base-8)或十六进制(base-16)表示。对于八进制值,反斜杠后直接跟数字;而对于十六进制,反斜杠后插入一个x
字符,然后是十六进制数字本身(例如:\x20 或 \x4A)。
多个字符串字面量可以通过用一个或多个空白字符(包括制表符、换行符和其他有效的空白字符)分隔它们来连接形成单个字符串字面量。例如:
"this forms" "a single" " string "
"of characters"
以上是一个等同于以下的字符串字面量:
"this formsa single string of characters"
注意引号内的空格是字面量的一部分,而引号外的不是。
一些程序员还使用一种技巧将长字符串字面量包含在多行中:在C++中,行末的反斜杠(\)被视为行续延字符,它将该行和下一行合并为一行。因此,以下代码:
x = "string expressed in \
two lines"
等同于:
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 | 字符串字面量是一个原始字符串(raw string) |
在原始字符串中,反斜杠和单引号、双引号都是有效字符;字面量的内容由初始R"_sequence_(and a final)_sequence_"
限定,其中_序列_
是任何字符序列(包括空序列)。字符串的内容是括号内的内容,忽略限定序列本身。例如:
R"(string with \backslash)"
R"&%$(string with \backslash)&%$"
上面的两个字符串都等同于"string with \\backslash"
。R
前缀可以与任何其他前缀组合,如u
、L
或u8
。
其他字面量(Other literals)
C++中存在三个关键字字面量:true
、false
和nullptr
:
true
和false
是bool
类型变量的两个可能值。nullptr
是空指针值。
bool foo = true;
bool bar = false;
int* p = nullptr;
类型常量表达式(Typed constant expressions)
有时,给常量值命名是很方便的:
const double pi = 3.1415926;
const char tab = '\t';
然后我们可以使用这些名字来代替它们所定义的字面量:
#include <iostream>
using namespace std;
const double pi = 3.14159;
const char newline = '\n';
int main ()
{
double r=5.0; // 半径
double circle;
circle = 2 * pi * r;
cout << circle;
cout << newline;
}
预处理器定义(#define)
另一个为常量命名的机制是使用预处理器定义。它们具有以下形式:
#define identifier replacement
在此指令之后,代码中任何出现的identifier
都会被解释为replacement
,其中replacement是任意字符序列(直到行尾)。此替换由预处理器执行,在程序编译之前发生,因此导致了一种盲替换:不以任何方式检查涉及的类型或语法的有效性。
例如:
#include <iostream>
using namespace std;
#define PI 3.14159
#define NEWLINE '\n'
int main ()
{
double r=5.0; // 半径
double circle;
circle = 2 * PI * r;
cout << circle;
cout << NEWLINE;
}
注意,#define
行是预处理器指令,因此是单行指令——与C++语句不同——不需要在末尾加分号(;);指令自动扩展到行尾。如果在行中包含分号,它将成为替换序列的一部分,并在所有替换的情况下包括在内。