头文件未加守卫宏导致重复定义是最常见原因,需用#ifndef/#define/#endif包裹;结构体等系统命名冲突应通过条件编译或改用系统头文件解决;变量函数定义须分离声明与实现,避免头文件中直接定义。

头文件没加守卫导致重复展开
这是最常见原因:一个 .h 文件被多个 .c 或 .cpp 文件包含,预处理器把里面的内容原样复制了多遍,结构体、宏、const 变量就变成了多次定义。
解决方法很简单,在头文件开头和结尾加上标准守卫宏:
#ifndef MY_HEADER_H#define MY_HEADER_H- ……你的声明和定义……
#endif
注意宏名要唯一,一般用大写文件名加 _H 后缀;如果头文件里只放声明(比如函数原型、extern 变量、class 定义),那守卫就够了;但如果写了 const int x = 42; 或 inline 以外的函数实现,还得配合 extern 或移到 .c 里。
struct 在多个系统头文件中冲突
像 struct _wfinddata_t、struct sched_attr、struct user_hwdebug_state 这类名字,可能既出现在 MinGW 的 io.h 里,又出现在 GCC 的 C++ 标准库头(如 cwchar)包含的 wchar.h 里,或者 glibc 2.41+ 新增了 linux/sched/types.h 中的定义,而你的代码又手动写了一遍。
这时不能硬删,得靠条件编译绕开:
- 查系统是否已定义对应宏,比如 glibc 用
#ifndef SCHED_ATTR_SIZE_VER0 - MinGW 下可尝试在包含冲突头之前加
#define __need_struct__wfinddata_t(具体看头文件是否支持) - 更稳妥的做法是:移除你代码里的手动定义,改用系统头,例如
#include <linux></linux>
别指望改 MinGW 路径能根治——路径一换,可能又撞上别的头文件顺序问题。
变量或函数在头文件里直接定义
写 int global_counter = 0; 或 void helper() { ... } 在头文件里,等于告诉每个包含它的 .c 文件:“请各自造一个同名变量/函数”。链接时必然报 redefinition of 'xxx'。
正确做法分清楚声明和定义:
- 头文件里只写
extern int global_counter;和void helper(); - 选且仅在一个
.c文件里写int global_counter = 0;和函数完整实现 - 如果真想在头里放实现,必须加
inline(C99+/C++)或static inline(兼容老编译器)
尤其注意 C++ 里带默认参数的函数声明和定义不能拆开放——声明在头、定义在 .cpp 里时,= 0 只能出现在声明处。
同一个源文件里重复定义同名标识符
看起来低级,但实际高频:比如在 main() 里写了两遍 int fd;,或在全局作用域写了两个 struct config { ... };。GCC 报错行号会直接指到第二次出现的位置。
检查点很具体:
- 是不是忘了删调试时临时加的变量声明?
- 是不是 copy-paste 时漏改了结构体名,导致两个
struct msg_header { ... };并存? - 是不是用了宏生成结构体,但宏没做唯一性处理,被展开两次?
这类错误不涉及头文件机制,纯属手误,但 grep 搜索 struct xxx 或 int xxx 往往比看报错更快定位。
真正容易被忽略的是:有些重定义发生在宏展开后,肉眼看不见。用 gcc -E file.c | grep -A5 -B5 'your_symbol' 看预处理结果,才能确认它到底被展开了几次。


















