537 字
3 分钟
03用extern解决重定义
2025-01-09

重定义问题#

问题:假设存在以下三个C++文件,编译会报错。

global.h: 定义两个变量

#pragma once
#include <string>
int global_val = 10;
std::string global_str = "hello";

global.cpp: 直接包含头文件

#include "global.h"

main.cpp: 同样包含头文件

#include <iostream>
#include "global.h"
int main()
{
std::cout << "global_val is " << global_val << std::endl;
std::cout << "global_str is " << global_str << std::endl;
std::cout << "Hello World!\n";
return 0;
}
/*** 报错如下 ***
1>global.obj : error LNK2005: "int global_val" (?global_val@@3HA) 已经经在 externs_demo.obj 中定义
1>global.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > global_str" (?global_str@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) 已经在 externs_demo.obj 中定义
1>D:\dev\cpp\Cpp_Basic\externs_demo\x64\Debug\externs_demo.exe : fatal error LNK1169: 找到一个或多个多重定义的符号
*/

报错LINK,表示在链接global.obj文件时产生了错误,报错信息显示,global_valglobal_str已经在externs_demo.obj定义了。

解释如下:

  1. 后缀为cpp的源文件会分别预编译global.h的内容,然后各自定义global.h中的变量。
  2. 在本示例中,main.cpp先编译,得到了externs_demo.obj文件,随后global.cpp编译后,与externs_deme.obj链接时,就发现了重复定义的错误。

extern#

extern关键字,主要用于在头文件声明一个全局变量/函数,且这个全局变量/函数会在另一个文件或者同一个文件的其他位置(多处)定义。确保在多个源文件引用同一个头文件时,能够正确地链接到这个全局变量/函数的定义。

解决方法:

  • 声明和定义分开,在头文件中只声明变量(使用extern关键字)
  • 在源文件中定义变量。

注:当不使用extern关键字时,编译器不会只声明变量,而是会直接初始化(定义)变量

global.h:添加extern关键字,去除定义变量的相关代码。

#pragma once
#include <string>
extern int global_val;
extern std::string global_str;

const的特殊性#

当在头文件定义了const变量时,且这个头文件被多个源文件包含。

此时编译器会在.rodata中定义多个不同的const变量(这些变量的地址不同)

但是,如果在头文件中使用extern关键字声明const变量,那么编译器只会在对应的源文件中,定义一个const变量。

03用extern解决重定义
https://chrisnake11.github.io/blog/posts/coding/c基础/03用extern解决重定义/
作者
Zheyv
发布于
2025-01-09
许可协议
CC BY-NC-SA 4.0