全局数组不能在头文件中定义,否则引发多重定义错误;应使用extern声明加单一.cpp定义,const数组可放头文件但有地址一致性风险,宏技巧可简化管理但需确保尺寸一致。

全局数组在头文件里直接定义会触发 multiple definition
只要你在 global.h 里写了 int my_array[10] = {0};,又让两个以上的 .cpp 文件包含它,链接时就必然报 multiple definition of 'my_array'。这不是编译错误,是链接器发现多个 .o 文件都提供了这个符号的定义,违反了 One Definition Rule(ODR)。数组和普通变量一样,不能在头文件中定义 —— 它不是 const、不是 inline、也不是模板,没有语言机制允许它被多次“看见”却只分配一次内存。
必须用 extern 声明 + 单一 .cpp 定义
这是最通用、最稳妥的做法,对任意大小、任意初始化方式的全局数组都有效:
- 在头文件中只写声明:
extern int my_array[10];(注意:尺寸可写可不写,但写上更清晰) - 在且仅在一个
.cpp文件(如globals.cpp)中写定义:int my_array[10] = {0}; - 所有要用它的源文件都
#include "global.h",不要 include.cpp - 如果数组需要初始化为非零值,初始化必须放在
.cpp的定义处,头文件里的extern声明不能带初始化器
const 全局数组可以放头文件,但要注意链接属性
如果你的数组是只读的,比如配置表或查找表,定义成 const 后,大多数编译器会把它放进只读段,并默认赋予 internal linkage(即每个翻译单元一份副本,但不参与链接冲突)。所以这样写通常不会报错:
// config.h
const char version_str[] = "v2.1.0";
const int lookup_table[] = {1, 4, 9, 16};
但要注意两点:
- 如果其他地方取了它的地址(比如传给函数),而你又希望所有模块看到的是同一个地址(而非多个副本),那仍然得走
extern+ 单一定义路径 - 某些老旧工具链或严格模式下,
const数组仍可能被当作外部符号处理,所以保险起见,大型项目里建议统一用extern方式管理所有全局数据
宏技巧能简化 extern 管理,但别滥用
当项目里有几十个全局变量/数组要导出时,挨个写 extern 很累。可以用条件宏切换语义:
// globals.h #ifndef GLOBALS_H #define GLOBALS_H #ifdef DEFINE_GLOBALS #define EXTERN #else #define EXTERN extern #endif EXTERN int sensor_data[256]; EXTERN float calibration_coeffs[12]; #endif
然后在唯一一个 globals.cpp 里:
#define DEFINE_GLOBALS #include "globals.h"
这样既保持单点定义,又避免重复劳动。但要注意:这个宏必须只在一个 .cpp 中定义,且不能出现在任何会被其他头文件间接包含的位置,否则会破坏语义。
真正容易被忽略的是数组尺寸一致性 —— 如果头文件里声明为 extern int buf[64],而 .cpp 里定义为 int buf[128],有些编译器不会报错,但运行时越界访问就很难排查。务必保证声明和定义的维度完全一致。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











