GCC链接器抱怨对现有全局变量的未定义引用

GCC linker complains about undefined reference to existing global variable

本文关键字:全局变量 未定义 引用 链接 GCC      更新时间:2023-10-16

我对GCC有问题。它找不到我的全局变量。我创建了一个示例C++项目来隔离这个问题:

a.cpp:

#include "b.h"
const char * const g_test = "blah blah";
int main(){
    test();
    return 0;
}

b.cpp:

#include <iostream>
#include "a.h"
using namespace std;
void test(){
    cout << g_test;
}

a.h:

extern const char * const g_test;

b.h:

void test();

我这样编译它:

$ g++ -o a.o -c a.cpp
$ g++ -o b.o -c b.cpp
$ g++ -o test a.o b.o
b.o: In function `test()':
b.cpp:(.text+0x7): undefined reference to `g_test'
collect2: error: ld returned 1 exit status

在最后一个命令中更改对象文件的顺序不会改变任何内容。

链接器为什么抛出错误?我本来只想创建一个可执行文件来打印"废话",但不知怎么的,错误出现了。我看不出有什么理由会失败。

作为常量变量,g_test只有内部链接,即只能在定义的.cpp文件中使用。为了给常量变量提供全局链接(即使其可从其他源文件中使用),您必须添加extern关键字,即:

#include "b.h"
extern const char * const g_test = "blah blah";
int main(){
    test();
    return 0;
}

或者,您可以在开头包含a.h。在这种情况下,编译器在翻译a.cpp时已知extern正向声明。

然而,最好的解决方案是将g_test的定义(没有extern关键字)移动到头文件中。原因是通过这种方式,编译器知道每个编译单元中g_test的定义,并且例如能够在编译时使用它来计算常量表达式。

最简单的解决方案是在定义中添加关键字extern。我知道这看起来很奇怪,extern通常将其作为前向声明,而不是定义,但编译器仍然会将其视为定义(实例化),因为你给了它一个值。

昆汀评论中的链接(从昆汀那里偷来)是对原因的极好解释。