📄 一句话概括
extern 用来声明"这个变量在别处有"——它不分配空间,只是告诉编译器"这个名字不是你这儿定义的,去别处找"。它是跨文件共享全局变量的手段,思路和 6.1.2 的函数声明完全一样。
📝 本节和前面几节的关系
前几节讲的都是"单个 .cpp 文件内"的变量。这一节第一次踏出单文件边界——多个源文件之间怎么共享一个变量。它也回到 6.1.2 的老套路:声明(打招呼)与定义(真身)分开。而 1.3.1 讲过的"编译 + 链接两步",正是在这里显出价值:extern 的账,要等链接器来结。
一、为什么需要 extern
一个工程里常有多个 .cpp 文件(1.3.1 讲过的多文件工程)。每个文件独立编译,编译器眼里只有自己这一个文件。
如果 b.cpp 想用 a.cpp 里定义的全局变量 g,编译 b.cpp 时编译器根本不知道 g 是什么。得先告诉它:
extern int g; // "有个叫 g 的 int,它在别处定义过了"
编译器于是放行,把"到底在哪"的问题留给链接器去解决。
二、定义 vs extern 声明
| 定义 | extern 声明 | |
|---|---|---|
| 写法 | int g = 100; |
extern int g; |
| 做什么 | 分配空间 + 给值 | 只告诉编译器这个名字存在 |
| 能写几次 | 整个工程只能一次 | 可以多次 |
| 放在哪 | 某个 .cpp 里 | 需要用它的 .cpp 里(或头文件里) |
记忆点:extern 声明不带初始值——一旦写成 extern int g = 100;,它就变成定义了(多处写会报"重复定义")。
三、动手 Demo:跨文件共享
这需要建一个工程(1.3.1 讲过怎么建),里面放两个 .cpp 文件。
文件一:data.cpp(定义者)
int g = 100; // 定义:这里真的分配了空间
int getG() {
return g;
}
文件二:main.cpp(使用者)
#include <iostream>
using namespace std;
extern int g; // 声明:g 在别的文件里
int getG(); // 函数也一样要声明(6.1.2)
int main() {
cout << "从 data.cpp 拿到的 g = " << g << endl;
g = 200; // 改它:改的就是同一个变量
cout << "改完之后 getG() 返回 = " << getG() << endl;
return 0;
}
看到什么算成功:
从 data.cpp 拿到的 g = 100
改完之后 getG() 返回 = 200
第二行证明"两个文件操作的是同一个变量":main 里改了 g,data.cpp 里的函数读出来也是 200。
30 秒实验(在单文件里也能做):
#include <iostream>
using namespace std;
extern int g; // 声明
int g = 100; // 定义
int main() {
cout << g << endl; // 100
return 0;
}
把 int g = 100; 这一行注释掉再编译——报错是:
undefined reference to `g'
注意这是"链接错误"而不是"编译错误":编译器已经认下了这个名字(因为声明在),是链接器最后没找到真身才报的。undefined reference 这个报错就是 extern 的标志脸。
四、extern 的两个常见搭档
- 配
const做跨文件常量:extern const double PI;(在别处定义)。不过更常见的做法是把常量直接写进头文件。 extern "C":让 C++ 代码能调用用 C 语言写的函数(按 C 的规则处理函数名)。调用系统库时常见,先记个印象。
五、常见误区
- "extern 是定义"——不是,是声明。写成
extern int g = 100;就变成定义,多处写会报重复定义。 - "extern 变量不占内存"——声明不占;但它指向的那个定义当然占(归定义所在的文件管)。
- "extern 在单文件里也有用"——基本没用。它的舞台是多文件工程。
- "extern 和 static 没关系"——其实是一对:
static让全局变量只在本文件可见,extern让别处也能用它(回顾 6.7.2 的第三种用法)。 - "链接错误和编译错误差不多"——这是本章最值得记住的一个区分:
- 编译错误:编译器看不懂(语法、未声明、类型不匹配)
- 链接错误:编译器看懂了,但拼装时找不到真身(
undefined reference) - 回看 1.3.1 的"编译 + 链接两步"——extern 就是这条分界线的活教材。
自测三问(点开对答案)
1. extern 是声明还是定义?——声明,不分配空间。 2. 它解决什么问题?——让多个 .cpp 文件共享同一个全局变量。 3. `undefined reference` 是编译错误还是链接错误?——链接错误(编译器认了名字,链接器找不到真身)。- ☐ 6.8 小结(下一节)
相关笔记
- static变量 —— 全局 static 是它的"对面"
- 函数的声明 —— 声明与定义的分工
- C++工程项目文件 —— 编译与链接两步
- 🔷 C++基础 · 索引 —— 全课路线图