4.extern.md 4.5 KB

extern

判别规则(核心,唯一要记的)

  • 跨文件共享 = 一个文件定义(不带 extern)+ 其他文件用 extern 声明(不带初始化)
  • 判断声明/定义:extern + 无初始化 = 声明;否则(无 extern 或带初始化)= 定义
    • 陷阱:extern int x = 5; 带初始化 → 是定义,extern 被"升级"成定义

一句话:"extern 只借不造——声明是借,定义是造;借了没人造就链接报错,造了两次也报错。"

抽象描述(一句话本质)

extern 是跨文件共享的"介绍信"——告诉编译器这个变量/函数在别的文件里已定义,这里只是引用,不分配存储。函数声明默认就是 extern。

正反例(建立直觉)

  • 正例1file1.c: int counter = 0;(定义,分配内存)+ file2.c: extern int counter;(声明,不分配)→ file2.c 能正常读写 counter
  • 正例2:跨文件共享函数 file1.c: int add(int a,int b){...} + file2.c: extern int add(int,int); → 可调用。函数声明默认 extern,不写也等价
  • 反例1:只声明没定义 → 编译能过,链接报 undefined reference(未定义引用)
  • 反例2:两个文件都定义没加 static → 链接报 multiple definition(重复定义)。解决:一个定义 + 一个 extern 声明,或都加 static 私有化

易混对比

定义 声明
写法 int x = 5;(无 extern / 带初始化) extern int x;(extern + 无初始化)
分配内存 ✅ 分配 ❌ 不分配
能出现几次 整个工程只能 1 次 可以很多次
常见报错 重复定义(多个定义) 未定义引用(只有声明没定义)

变体验证(3 题,全过=学会)

  1. file1.c: int num = 10; + file2.c: extern int num; num++; → 链接成功,num = 11
  2. 陷阱题:头文件 common.hint global;,a.c 和 b.c 都 include → 报"重复定义"错误。因为 #include 是文本展开,两个文件各有一份定义(外部链接)
  3. file2.c: extern int counter; 但 file1.c 定义的是 static int counter;链接失败。static = 内部链接,只登记在自己 .o 内部符号表、不进全局符号表,extern 去全局表找不到 → undefined reference。extern 突破不了 static

口述要点(面试怎么讲)

  • 结论先行:声明是借、定义是造;定义只能有一份,其他文件 extern 声明引用
  • 头文件正误姿势:头文件只写 extern int x;(接口),定义 int x = 0; 只放唯一一个 .c(实现);多个文件 #include "x.h" 全都能用
  • 为什么不 include .c 文件:include .c = 把实现原样复制进每个文件 → 每个文件都有一份实现 → 重复定义;且 .c 是实现、头文件是接口,include 实现文件会编译变慢、依赖混乱、破坏架构分层
  • 易错点extern int x = 5; 带初始化是定义不是声明;函数声明默认 extern 可省

关系网络

相邻概念 和 extern 的关系 孤立理解会犯的错
static 双胞胎,正好相反:static = 内部链接(锁文件内),extern = 外部链接(跨文件共享) 以为 extern 能突破 static——不能,链接器不看内部符号
#include extern 是"借"(声明,不分配),include 是"展开"(文本粘贴) 以为 include 头文件 = 定义了变量
声明 vs 定义 extern + 无初始化 = 声明;无 extern 或带初始化 = 定义(extern int x = 5; 是定义!) 以为 extern 永远只是声明
头文件 头文件放 extern 声明 = 接口;.c 放定义 = 实现 头文件放定义 → 多文件 include 重复定义报错

学习日期

2026-08-03


每主题一页,复习时只翻本目录。