C++ 常量/字面值
C++ 常量和字面量
Section titled “C++ 常量和字面量”字面量(Literals)(通常也被称为常量)是直接嵌入源代码中的固定值。它们表示特定数据,如数字、字符或字符串。
常量(Constants),从更广泛的意义上讲,是指初始化后其值不能更改的标识符(类似于变量)。现代 C++ 提供了几种定义常量的方式。
C++ 支持各种类型的字面量:
1. 整型字面量
Section titled “1. 整型字面量”表示整数。它们可以用不同的进制指定:
- 十进制 (base 10): 默认,无前缀(例如
123,-45)。 - 八进制 (base 8): 前缀
0(例如0173,即十进制的 123)。避免使用前导零,除非是八进制,因为它可能会引起混淆。 - 十六进制 (base 16): 前缀
0x或0X(例如0x7B或0X7b,两者都是十进制的 123)。使用数字 0-9 和字母 a-f(或 A-F)。 - 二进制 (base 2) (C++14): 前缀
0b或0B(例如0b01111011,即十进制的 123)。
整型字面量可以带有后缀来指定其类型:
u或U:unsigned(例如123u)。l或L:long(例如123L)。ll或LL(C++11):long long(例如123LL)。- 可以组合使用(例如
123UL,45ull)。
C++14 引入了数字分隔符(单引号 ')以提高可读性:
long long big_number = 1'000'000'000LL; // 更易读int binary_flags = 0b1101'0010'1010'0001;2. 浮点型字面量
Section titled “2. 浮点型字面量”表示带有小数部分的数字。它们可以用十进制或指数表示法书写:
- 十进制: 必须包含小数点 (
.) 或指数(例如3.14159,12.0,.5,5.)。 - 指数表示法: 使用
e或E,后跟可选的符号和一个整数指数(10 的幂)(例如6.022e23,1.6E-19)。 - 也存在十六进制浮点型字面量(使用
0x前缀和p表示指数),但较不常用(0x1.921fb5p+1)。
后缀指定其类型:
- 无后缀:
double(默认)。 f或F:float(例如3.14f)。l或L:long double(例如3.1415926535L)。
也可以使用数字分隔符(')(C++14)。
double pi = 3.141'592'653'589'793;3. 布尔型字面量
Section titled “3. 布尔型字面量”表示布尔值:
true:表示布尔值 true。false:表示布尔值 false。
4. 字符字面量
Section titled “4. 字符字面量”表示单个字符,用单引号(')括起来。
- 普通
char:'a','?','7'。类型为char。 - 宽字符(Wide Character):
L'β'(前缀L)。类型为wchar_t。 - UTF-8 (C++11):
u8'貓'(前缀u8)。类型为char(C++11/17) 或char8_t(C++20)。 - UTF-16 (C++11):
u'Ω'(前缀u)。类型为char16_t。 - UTF-32 (C++11):
U'🌍'(前缀U)。类型为char32_t。
转义序列(Escape Sequences): 使用反斜杠(\)表示的特殊字符:
| 转义序列 | 含义 |
|---|---|
| \ | 反斜杠 (\) 字符 |
| ’ | 单引号 (') 字符 |
| ” | 双引号 (") 字符 |
| ? | 问号 (?) 字符 |
| \n | 换行符 |
| \t | 水平制表符 |
| \v | 垂直制表符 |
| \b | 退格 |
| \r | 回车 |
| \f | 换页 |
| \a | 响铃 |
| \0 | 空字符 |
| \ooo | 八进制值(最多 3 位) |
| \xhh… | 十六进制值 |
| \uHHHH (C++11) | 通用字符名称(Unicode - 16 位) |
| \UHHHHHHHH (C++11) | 通用字符名称(Unicode - 32 位) |
5. 字符串字面量
Section titled “5. 字符串字面量”表示字符序列,用双引号(")括起来。它们隐式地以空字符结尾(会自动添加一个 \0 字符)。
- 普通:
"Hello, World!"(类型为const char[])。 - 宽字符:
L"你好"(前缀L)。类型为const wchar_t[]。 - UTF-8 (C++11):
u8"κόσμε"(前缀u8)。类型为const char[](C++11/17) 或const char8_t[](C++20)。 - UTF-16 (C++11):
u"नमस्ते"(前缀u)。类型为const char16_t[]。 - UTF-32 (C++11):
U"שלום"(前缀U)。类型为const char32_t[]。 - 原始字符串字面量(Raw String Literals)(C++11):
R"(No\escape\needed)"或R"delimiter(Text)delimiter"。对于包含许多反斜杠或引号的字符串非常有用。
相邻的字符串字面量会被编译器连接起来:
std::cout << "This is part 1, " "and this is part 2.\n";6. 指针字面量
Section titled “6. 指针字面量”nullptr (C++11): 表示空指针值。它是类型安全的,在表示空指针时比 0 或 NULL 更推荐使用。
常量是初始化后其值不能更改的命名实体。现代 C++ 提供了两种主要方式:
1. const 关键字
Section titled “1. const 关键字”const 限定符将对象声明为不可变的。其值必须在声明时初始化,并且之后不能修改。const 变量具有与普通变量相同的作
#include <iostream>
int main() { const int MAX_USERS = 100; const double PI = 3.14159; const char NEWLINE = '\n';
// 错误!不能赋值给 const 变量。 // MAX_USERS = 200;
// 使用常量 double circumference = 2 * PI * 5.0; std::cout << "Max users: " << MAX_USERS << NEWLINE; std::cout << "Circumference: " << circumference << NEWLINE;
return 0;}相比于 #define,使用 const 定义常量更受推荐,因为它是类型安全的并且遵循作用域规则。
2. constexpr 关键字 (C++11)
Section titled “2. constexpr 关键字 (C++11)”constexpr 声明一个表达式 可以 在编译时求值。当应用于变量时,它隐含了 const 属性,并要求初始化表达式是一个编译时常量表达式。
constexpr 允许在需要编译时求值的上下文中使用常量,例如数组边界(在 C++11 VLAs 之前)、模板参数和枚举初始化器。
#include <array> // 用于 std::array
constexpr int get_array_size() { return 5 * 2;}
int main() { constexpr int COMPILED_SIZE = 10; constexpr double GRAVITY = 9.80665; constexpr int DYNAMIC_SIZE = get_array_size(); // 在编译时求值
int myArray[COMPILED_SIZE]; // OK: COMPILED_SIZE 是编译时常量 std::array<double, DYNAMIC_SIZE> stdArray; // OK: DYNAMIC_SIZE 是编译时常量
// 错误!constexpr 隐含了 const // GRAVITY = 9.9;
return 0;}最佳实践: 对于可以在编译时求值的常量,优先使用 constexpr。对于在运行时初始化但之后不应更改的值,使用 const。
避免使用 #define 定义常量
Section titled “避免使用 #define 定义常量”预处理器指令 #define 也可以为值创建符号名称(宏)。
#define MAX_ITEMS 10 // 旧的 C 风格,不建议用于常量然而,在现代 C++ 中通常不鼓励使用 #define 定义常量,原因如下:
- 它缺乏类型信息(只是简单的文本替换)。
- 它不遵循作用域规则(宏在定义后在整个翻译单元中是全局的)。
- 由于宏展开规则,它可能导致意外的行为。
- 它不容易调试(调试器看到的是替换后的值,而不是宏名称)。
因此,请使用 const 或 constexpr 来代替,以获得类型安全和更好的代码结构。