extern 是 C++ 中用于控制变量 / 函数的作用域和链接属性的关键字,核心作用只有两个:
- 声明外部变量 / 函数(告诉编译器:这个符号在其他文件中定义,不要报错)
- 实现 C 语言兼容链接(解决 C++ 函数名修饰导致的链接问题)
它的核心特点:extern 是声明,不是定义,不会分配内存。
一、基础用法:跨文件访问全局变量 / 函数
C++ 中,全局变量和函数默认是外部链接(其他文件可访问),但需要用 extern 声明才能在其他文件中使用。
1. 跨文件使用全局变量
场景:两个 .cpp 文件共享一个全局变量
// file1.cpp 定义全局变量(分配内存)int g_count = 10; // 定义:初始化+分配内存
// file2.cpp 声明外部变量(不分配内存)extern int g_count; // 告诉编译器:g_count 在其他文件定义voidtest() {g_count = 20; // 直接使用,修改的是 file1 中的同一个变量}
✅ 关键规则:
- 定义:
int g_count = 10;只能出现一次(否则重复定义报错) - 声明:
extern int g_count;可以在多个文件中重复声明
不靠代码引用,靠链接器(Linker) 找到
C++ 程序生成分 2 步:
- 编译:每个 .cpp 独立编译成 .o/.obj 文件
- 链接:链接器把所有 .o 文件合并,自动查找全局变量 / 函数的定义
推荐结构(项目标准写法)
common.h(头文件,只放声明)
#pragma onceextern int g_count;
#include"common.h"int g_count = 10;
#include"common.h"// 包含声明即可voidtest(){g_count = 20;}
最核心的 3 点
- file2.cpp 不需要引用 file1.cpp
extern 只是告诉编译器:变量存在,别报错- 真正找到变量的是链接器,只要你把两个 cpp 一起编译就行
2. 跨文件使用函数
函数默认自带 extern,所以声明函数时可以省略 extern,效果完全一致:
// file1.cpp 定义函数intadd(int a, int b) {return a + b;}
// file2.cpp 声明外部函数externintadd(int a, int b); // 完整写法// int add(int a, int b); // 简化写法(推荐)
二、高级用法:extern "C"(C++ 调用 C 代码)
这是工作中最常用的场景!
问题根源
C++ 会对函数名做名称修饰(支持重载),而 C 语言不会。如果 C++ 直接调用 C 编写的库 / 函数,会因函数名不匹配导致链接错误。
解决方案
用 extern "C" 告诉 C++ 编译器:按照 C 语言的规则编译这个函数,不要修改函数名。
1. 单个函数声明
// C++ 文件中调用 C 函数extern "C" intadd(int a, int b); // 按 C 链接规则处理
2. 批量处理(头文件通用写法)
这是标准写法,兼容 C 和 C++ 编译:
// 头文件:common.h#ifndef COMMON_H#define COMMON_H// 仅在 C++ 编译时生效#ifdef __cplusplusextern "C" {#endif// 所有函数都按 C 链接规则编译intadd(int a, int b);voidlog(constchar* msg);#ifdef __cplusplus}#endif#endif
✅ 适用场景:
C++ 项目调用 C 语言编写的静态库 / 动态库 混合编程(C 调用 C++、C++ 调用 C)
三、extern 与 static 的区别
extern | |||
static |
❌ 错误用法:
// 不能同时用 extern 和 staticextern static int num; // 编译报错!矛盾
四、常见误区
extern声明不能初始化
extern int a = 10; // 错误!这变成了定义,失去 extern 作用externextern 只对全局变量 / 函数生效,局部变量无链接属性。extern 声明,定义放在 .cpp 文件中(避免重复定义)。五、总结
- 核心作用:跨文件声明符号(不分配内存)、C/C++ 兼容链接
- extern 变量:声明 → 其他文件找定义
- extern 函数:可省略,默认外部链接
- extern "C":解决 C++ 调用 C 代码的链接错误(工作必备)
- 与 static 对立:extern 跨文件,static 仅限当前文件
夜雨聆风