extern 与链接
跨文件共享符号。
extern 与链接 是 CoddyKit 上的免费 C Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。
什么是链接属性
链接属性描述一个名称是否可以在不同源文件之间共享。
具有外部链接属性的名称在整个程序中都指向同一个实体。具有内部链接属性的名称则只属于它所在的文件。理解链接属性是编写多文件程序的关键。
共享变量
假设两个文件都需要访问同一个全局计数器。您不能简单地在两个文件中分别定义它;这样会创建两个独立的变量,并导致重复符号链接错误。
正确做法是只定义一次,然后在其他所有地方使用 声明,并配合 extern。
/* config.c */
int g_count = 0; /* the one definition */extern 关键字
extern 告诉编译器,程序中的其他位置存在一个变量,但不会在当前位置为它创建存储空间。
它只是一个纯声明。链接器随后会将它解析到另一个文件中的唯一一个定义。
/* other.c */
extern int g_count; /* declared, not defined */
void bump(void) {
g_count++;
}在头文件中声明
规范的做法是:将 extern 声明放在头文件中,并将对应的定义放在且仅放在一个源文件中。
这样,任何包含该头文件的文件都可以使用这个共享变量。
/* config.h */
#ifndef CONFIG_H
#define CONFIG_H
extern int g_count;
#endif一个定义,多个声明
这就是针对全局变量的单一定义规则:变量可以在多个文件中使用 extern 进行声明,但只能在一个文件中定义。
唯一的定义(不带 extern)会分配存储空间。所有 extern 声明都只是指向这个定义。
/* config.h */ extern int g_count; /* declaration */
/* config.c */ int g_count = 0; /* definition */函数也具有外部链接属性
默认情况下,函数也具有外部链接属性,这就是为什么在头文件中放置函数原型后,其他文件就可以调用这些函数。
您可以在函数原型前写上 extern,但这没有必要;除非另有说明,函数默认就是外部的。
/* both forms mean the same */
int add(int a, int b);
extern int add(int a, int b);使用 static 实现内部链接属性
在文件作用域中使用 static 关键字,会让名称具有内部链接属性:它只能在所属的源文件中可见。
对于应当对模块保持私有的 helper 函数和全局变量,可以使用这种方式。其他文件既看不到它们,也不会与它们发生名称冲突。
/* parser.c */
static int line_no = 0; /* private to parser.c */
static void advance(void) { /* private helper */
line_no++;
}外部与静态链接属性对比
这两个关键字处于链接属性的两个相反端点。
extern 请求外部链接属性:在多个文件之间共享这个名称。文件作用域中的 static 强制使用内部链接属性:让这个名称保持私有。合理选择可以控制模块对外提供的内容。
extern int shared_total; /* visible everywhere */
static int local_cache; /* only this file */常见错误
初学者有时会将类似 int g_count; 的普通定义放入头文件。
由于头文件会被多个文件包含,每个文件都会得到自己的定义,于是链接器会报告重复符号。请始终在头文件中使用 extern 进行声明,并在一个 .c 文件中定义一次。
/* WRONG in a header included twice */
int g_count; /* multiple definition */
/* RIGHT */
extern int g_count; /* declaration only */整合起来
这种由三个文件组成的结构,是共享状态的标准方式。
头文件负责声明,一个源文件负责定义,其他文件包含头文件后使用它。链接器会将所有引用连接到这个唯一的定义。
/* config.h */ extern int g_count;
/* config.c */ #include "config.h"
int g_count = 0;
/* main.c */ #include "config.h"
/* uses g_count */初始化说明
只有真正的定义才应提供初始值:int g_count = 0;。
extern 声明不能进行初始化,因为它不会分配存储空间。写成 extern int g_count = 0; 会使其变成定义,从而违背使用 extern 的目的。
extern int g_count; /* ok: declaration */
extern int g_count = 0; /* becomes a definition */快速检查
检查您对 extern 和链接属性的理解。
回顾
您已经了解到,链接属性控制跨文件可见性。extern 声明在其他位置定义的名称;文件作用域中的 static 会让名称保持私有。
通过一个定义加多个 extern 声明来共享全局变量。接下来,我们将把这些文件编译并链接成一个程序。
常见问题解答
「extern 与链接」课时是免费的吗?
是的 — 「extern 与链接」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。
「extern 与链接」这节课中我会学到什么?
跨文件共享符号。 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「extern 与链接」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C Academy 课中编写并运行代码吗?
能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。