register 是一个老的"优化建议"——请编译器把这个变量放进 CPU 寄存器(最快的地方)。现代编译器早就不需要这个建议,它会自己分析并安排寄存器,所以 register 如今基本等于废弃。认得它就行,不必用。
6.7.1、6.7.2 讲了"住栈上"和"住静态区",这一节讲那个"想住进寄存器"的类别。它是四个存储类别里唯一一个"提议被历史否决"的——借它说明一个重要观念:优化交给编译器,人只负责把逻辑写清楚(和 6.6 内联函数的结论一脉相承)。
一、register 的初衷
CPU 里有一块特别小、特别快的存储区叫寄存器。同样的数据放在寄存器里,比放内存快得多。
register int i; // 老式写法:请求放进寄存器
for (i = 0; i < 1000000; i++) { } // 高频使用的循环变量
| 存储位置 | 速度 | 容量 |
|---|---|---|
| 寄存器 | 最快 | 极小(几十个) |
| 高速缓存 | 很快 | 小 |
| 内存 | 慢 | 很大 |
为什么当年要人手动提示:老编译器不够聪明,得靠人帮着指路。
二、现在的现实:建议已废
现代编译器比人更擅长分配寄存器:
- 它能看到整个函数、甚至跨函数的代码(内联之后)
- 它按"实际用得频不频繁"来决定谁进寄存器,比手写提示准得多
- 所以 register 很可能被完全忽略(标准也明确允许忽略它)
结论:现代 C++ 里 register 已不再是推荐写法,它属于历史遗留。
三、动手 Demo:它不改变任何结果
#include <iostream>
using namespace std;
int main() {
register int i; // 老式写法(Dev-C++ 里可能给警告)
long long sum = 0; // 用 long long,避免 2.3.3 的溢出
for (i = 1; i <= 1000000; i++) {
sum += i;
}
cout << "累加结果 = " << sum << endl;
return 0;
}
看到什么算成功:
累加结果 = 500000500000
(1 到 1000000 的和 = 1000000 × 1000001 ÷ 2 = 500000500000。)
这里有两件事要注意:
1. 加不加 register,输出完全一样、速度也基本无差别——这就是"它已被忽略"的直观证据。
2. Demo 用的是 long long 而不是 int——因为结果约 5000 亿,远超 int 上限(约 21 亿),用 int 会溢出回绕成乱七八糟的数(2.3.3 的老坑,这是它在本章第二次现身)。
30 秒实验:把 register 删掉再跑——输出一样,速度也一样。真想提速,要靠编译器的优化开关(如给编译器加 -O2)。记住这句话:优化是编译器的活,不是靠写关键字。
四、register 的三条老限制(了解即可)
| 限制 | 说明 |
|---|---|
| 不能取地址 | 寄存器没有内存地址,&i 不合法——这正好和 3.4"左值要有地址"呼应:它连地址都没有 |
| 不能是数组 / 结构体 | 只能装单个的简单变量 |
| 数量极少 | 就算编译器肯听,寄存器也就那么几个 |
第一条挺有意思:3.4 说"能站在 = 左边的东西必须有地址";而 register 变量恰恰可能没有地址——它是左值概念的一个边界案例。
五、常见误区
- "写了 register 一定变快"——没有保证,通常直接被忽略。
- "register 是 C++ 推荐写法"——早就不推荐了,属于历史遗留。
- "优化只能靠程序员手写提示"——反了。高级优化(内联、寄存器分配、循环展开)都是编译器的活(回顾 6.6 的内联同理)。程序员的职责是把逻辑写清楚、把算法选对。
- "那学它还有什么用"——三个用处:① 看懂老代码;② 理解"存储位置影响速度"这件事;③ 记住"别和编译器抢活干"这条工程观念。
自测三问(点开对答案)
1. register 是什么?——一个老式的优化建议,请求把变量放进 CPU 寄存器。 2. 现在还有用吗?——基本没用了,现代编译器自动完成寄存器分配,会忽略这个建议。 3. register 变量能取地址吗?——不能,寄存器没有内存地址。- ☐ 6.7.4 extern变量(下一节)
相关笔记
- 内联函数 —— 同样是"把优化交给编译器"
- 判断左值与右值 —— "左值要有地址"的边界案例
- 整型变量 —— Demo 里为何用 long long
- 🔷 C++基础 · 索引 —— 全课路线图