本章目标:搞懂整数、浮点数、布尔、字符串、auto、常量。 这是全书的基石,请务必动手验证每个例子。
变量就是"盒子上贴了标签"。声明变量 = 声明盒子和标签:
int age = 18; // int 是"整数"类型
age = 19; // 把盒子里的值改成 19
std::println("{}", age); // 打印 19
格式:类型 名字 = 初值;
| 类型 | 大小(常用平台) | 取值范围 |
|---|---|---|
| int | 4 字节(32bit) | 约 ±21 亿 (2^31-1) |
| unsigned | 4 字节 | 0 ~ 约 42 亿 |
| long | 8 字节(64bit) | 极大,写大数用它 |
| long long | 8 字节 | 同 long 差不多,明确就是 8 字节 |
| short | 2 字节 | 约 ±3.2 万 |
| char | 1 字节 | 存一个字符/小整数,-128~127 |
注意:
int x = 2147483647; // int 最大值
x = x + 1; // 变成 -2147483648!悄无声息
这是 C++ 最经典的坑之一,以后做计算要想着范围。
保证不会为负时再用它。新手别乱用,容易出 bug。
double price = 3.14; // 双精度,绝大多数情况用它
float f = 2.5f; // 单精度,省内存但精度低
规则:
需要比较时用"差小于一个极小值":
double a = 0.1 + 0.2;
if (std::abs(a - 0.3) < 1e-9) { /* 算它俩相等 */ }
bool ok = true; // 只有两个值:true / false
bool no = false;
打印 bool 会显示 1 或 0,想显示 true/false 需要设置格式:
std::println("{} {}", true, false); // 1 0
std::println("{:b} {:b}", true, false); // true false
char c = 'A'; // 单引号 = 一个字符
std::string s = "你好"; // 双引号 = 字符串(多字符)
// 注意:std::string 需要 #include <string>
char 本质是小整数('A' 就是 65),所以可以参与算术:
char b = c + 1; // 'B'
字符串的常用操作后面有专门一章(第六章),这里先认识它。
auto x = 42; // 编译器自动推断:x 是 int
auto y = 3.14; // y 是 double
auto s = std::string("hi"); // s 是 string
好处:
坏处(唯一一个):你自己看不出类型是什么。 需要确认真实类型时,用 static_assert 验证:
auto x = 42;
static_assert(std::is_same_v<decltype(x), int>); // 编译期检查
(这行看不懂没关系,第七章后自然懂,此处只是展示"可验证")
const int MAX_USERS = 100; // const:运行时不可改
constexpr int MAX = 100; // constexpr:编译期就定死
区别(人话版):
比如数组大小。性能好,因为运行时根本没有这个变量。
经验法则:能 constexpr 就 constexpr,否则用 const。 宏 #define 是老 C 风格,现代 C++ 禁止用它定义常量。
一个编译期计算的例子:
constexpr int square(int n) { return n * n; }
constexpr int r = square(5); // 编译时就算出 25
1) 隐式转换(编译器自动做,但可能有坑):
int x = 3.9; // 小数截断成 3,没有警告(新版 clang 会警告)
double y = 3; // 整数升成 3.0,安全
2) 强制转换(你明确要求,C++ 老风格,不推荐):
int x = (int)3.9; // 3
3) 现代转换(推荐):
int x = static_cast<int>(3.9); // 3,静态转换
// static_cast 以外的 cast 后面指针章节会提
一句话:小数转整数 = 直接丢掉小数部分(不是四舍五入)。
int a = 5; // 老式
int b(5); // 括号式
int c{5}; // 花括号式(推荐,C++11 起)
int d{}; // 花括号空 = 初始化为 0
花括号的好处:不允许"缩窄"转换,比如 int x{3.9} 编译报错, 这能拦住大量隐性 bug。习惯用 {} 初始化。
int n = 10;
int& ref = n; // ref 是 n 的别名,不是拷贝!
ref = 20; // 改 ref 就是改 n
std::println("{}", n); // 20
& 在类型里 = "引用"。引用必须初始化,且绑定后不能换人。 引用是后面学函数参数的关键,现在先混个脸熟。
练习题