声明不分配内存(如extern int x;),定义分配内存(如int x;或int x=42;),这是区分二者的唯一可靠判据。

变量声明和变量定义在C++里不是一回事,搞混了轻则编译警告、链接失败,重则运行时读到垃圾值甚至崩溃。核心就一条:extern int x; 是声明,int x; 或 int x = 42; 是定义。
怎么一眼看出是声明还是定义
看是否分配内存——这是唯一可靠判据。声明只让编译器“认识这个名字”,不占内存;定义则真金白银地分配空间(全局在.bss或.data段,局部在栈上)。
-
extern int a;:纯声明,不分配内存,符号表里标为UND -
int a;:定义(也是声明),全局变量默认零初始化,分配4字节 -
int a = 0;:定义+显式初始化,存入.data段,汇编里有.long 0 -
extern int a = 1;:虽带extern,但因有初始化,仍是定义(且是外部链接定义)
为什么头文件里不能写 int global_var;
因为每个包含它的 .cpp 文件都会生成一份定义,链接时触发 ODR 违反,报 multiple definition of 'global_var' 错误。
- 正确做法:头文件里只放
extern int global_var;,一个 .cpp 里写int global_var = 42; - 例外:C++17 起可用
inline int global_var = 42;,它允许在头文件中定义,链接器会自动合并 - const 全局变量(如
const int MAX = 100;)也可放头文件,因为默认内部链接,不冲突
常见坑:声明和定义类型不一致
比如在 file1.cpp 定义了 float g_val = 3.14f;,却在 file2.cpp 声明成 extern int g_val;,编译能过,但链接后读取时会把 float 的二进制位当 int 解释,结果完全不可预测。
- 这种错误不会被编译器捕获,只有运行时出问题,极难调试
- 结构体声明更危险:
struct S;是不完整声明,没定义,sizeof(S)直接报错 - 函数声明也要严格匹配签名,
void f(int);和void f(long);是两个不同函数
最易被忽略的点是:局部变量 int x; 是定义,但它不初始化——值是栈上残留的随机垃圾;而全局 int x; 却会被零初始化。这个差异不是语法问题,而是存储期和内存段决定的,写错位置就等于埋雷。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











