C语言头文件多重包含疑义与链接重定义问题排查
解决头文件const变量引发的"multiple definition"链接错误
最近我碰到一个嵌入式项目的问题,跟你分享一下排查和解决的过程:
我手里是个只有少量.c和.h文件的小型项目,之前一直受多重包含问题困扰。于是我搞了个master.h头文件,把所有需要的头文件都塞进去,而且所有头文件都加了#ifndef _MY_HEADER #define _MY_HEADER … #endif的保护宏,每个源文件顶部都包含这个master.h。本以为这样就能彻底杜绝多重包含了,结果编译后却弹出了链接错误:
Building target: My_Project_Bootloader.axf Invoking: GNU ARM C Linker arm-none-eabi-gcc -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -T "C:/Users/Greg/SimplicityStudio/v4_workspace/My_Project_Bootloader/GNU ARM v4.9.3 - Debug/My_Project_Bootloader_custom.ld" -nostdlib -L"C:\GCC_STUFF" --specs=nosys.specs -Xlinker --gc-sections -Xlinker -Map="My_Project_Bootloader.map" -lm -lgcc -lc -o My_Project_Bootloader.axf "./Source/aeabi_memset-thumb.o" "./Source/crt0.o" "./Source/em_emu.o" "./Source/functions.o" "./Source/main.o" "./Source/startup_efm32jg1b.o" "./Source/interrupts.o" ./Source/main.o:(.rodata.const_ModBusIDReg+0x0): multiple definition of `const_ModBusIDReg' ./Source/functions.o:(.rodata.const_ModBusIDReg+0x0): first defined here collect2.exe: error: ld returned 1 exit status make: *** [My_Project_Bootloader.axf] Error 1
一开始我以为还是多重包含的问题,但仔细排查后发现,这根本不是头文件重复包含导致的,而是因为我在头文件里直接完成了const变量的声明和定义。
在C语言里,哪怕是const变量,如果在头文件中直接定义(也就是同时赋值),每个包含该头文件的.c文件都会生成一个这个变量的独立副本。当链接器把所有目标文件拼在一起时,就会发现同一个变量被定义了多次,自然就抛出"multiple definition"的错误了——头文件保护宏只能防止单个源文件里重复包含头文件引发的编译错误,管不了多个源文件生成多个变量副本的链接问题。
解决方法很简单,遵循头文件只声明、源文件才定义的原则:
正确写法示例
头文件(仅声明)
// boot.h // 只声明const数组,不做初始化(即不定义) const unsigned char const_ModBusIDReg[7][48];
源文件(定义并初始化)
// boot.c #include "boot.h" // 在这里完成const数组的定义和初始化 const unsigned char const_ModBusIDReg[7][48] = { "String1", // reg00 "String2", // reg01 "String3", // reg02 "String4", // reg03 "String5", // reg04 "String6", // reg05 "String7" // reg06 };
这样修改后,整个项目里只有boot.c里有const_ModBusIDReg的定义,其他源文件通过头文件的声明来引用这个变量,链接器就不会再报错了。
内容的提问来源于stack exchange,提问作者Gregory Helton
相关产品推荐
相关产品推荐

