根本原因是只声明未定义:extern仅声明变量存在,链接时需在某个.cpp中用int var;定义以分配存储空间;头文件中放extern声明可共享,但禁止定义,const变量需显式extern声明并单独定义。

extern 声明变量时,为什么链接时报错 undefined reference to 'xxx'
根本原因:只声明没定义。extern 只告诉编译器“这个变量在别处定义”,但若整个项目里没有任何地方用 int g_count; 这种形式真正分配存储空间,链接器就找不到它。
- 必须且仅在一个 .cpp 文件里做**定义**(不带
extern),例如:int g_config_flag = 1; - 其他所有用到它的 .cpp 或 .h 里,统一用
extern int g_config_flag;声明 - 头文件中放
extern声明是安全的;但**绝不能在头文件里写定义**(否则多个 cpp 包含后会重复定义) - 如果变量是 const 全局,C++ 默认内部链接(
static),需显式加extern const int g_version;并在某处定义,否则其他文件看不到
头文件里写 extern 和直接在 .cpp 里写,有啥区别
本质没区别,但组织方式影响可维护性。头文件集中声明,是多人协作和多文件引用的前提。
- 头文件(如
global.h)里放:extern std::string g_app_name;—— 所有需要它的 .cpp 都#include "global.h" - 若只在某个 .cpp 里写
extern,那只有它自己能访问,失去“共享”意义 - 注意:头文件中不要写初始化,
extern int x = 42;是非法的(这是定义,不是声明) - 宏或内联函数替代部分全局变量更安全,但配置类、状态标志类变量仍常需
extern
C++ 中 extern "C" 和普通 extern 完全不是一回事
名字修饰(name mangling)导致的兼容问题。普通 extern 管变量/函数链接属性;extern "C" 是告诉 C++ 编译器:“按 C 的规则生成符号名”,主要用于混用 C 库。
-
extern int g_val;→ 让链接器找一个叫g_val的符号(实际名可能是_Z5g_val) -
extern "C" int c_api_func();→ 符号名就是c_api_func,C 编译器也能识别 - 在头文件中混合使用时,常用
#ifdef __cplusplus包裹:extern "C" { ... } - 误把
extern "C"当作“跨文件共享变量”的解决方案,会导致链接失败或调用错乱
多线程下 extern 全局变量的读写要特别小心
extern 不提供任何线程安全保证。多个线程同时读写同一个 extern 变量,结果不可预测。
立即学习“C++免费学习笔记(深入)”;
- 纯读操作一般没问题(只要初始化完成且不被修改)
- 写操作必须加同步:用
std::mutex、std::atomic或std::call_once控制初始化 - 避免在
extern变量上做复合操作,比如g_counter++—— 它不是原子的 - 优先考虑用局部静态变量 + 函数封装(如
int& get_counter() { static int v; return v; }),比裸 extern 更可控









