🔷 第六章 函数
📄 一句话概括

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 变量恰恰可能没有地址——它是左值概念的一个边界案例。

五、常见误区

  1. "写了 register 一定变快"——没有保证,通常直接被忽略。
  2. "register 是 C++ 推荐写法"——早就不推荐了,属于历史遗留。
  3. "优化只能靠程序员手写提示"——反了。高级优化(内联、寄存器分配、循环展开)都是编译器的活(回顾 6.6 的内联同理)。程序员的职责是把逻辑写清楚、把算法选对。
  4. "那学它还有什么用"——三个用处:① 看懂老代码;② 理解"存储位置影响速度"这件事;③ 记住"别和编译器抢活干"这条工程观念。
自测三问(点开对答案) 1. register 是什么?——一个老式的优化建议,请求把变量放进 CPU 寄存器。 2. 现在还有用吗?——基本没用了,现代编译器自动完成寄存器分配,会忽略这个建议。 3. register 变量能取地址吗?——不能,寄存器没有内存地址。

相关笔记