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

GCC linker complains about undefined reference to existing global variable

我对 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

在上一个命令中更改目标文件的顺序不会改变任何内容。

为什么链接器会抛出错误?我原本希望只创建一个可执行打印 "blah blah",但不知何故出现了错误。我看不出它应该失败的任何原因。

作为 const 变量 g_test 只有内部链接,即只能在它定义的 .cpp 文件中使用。为了给一个 const 变量全局链接(即使其可从其他源文件使用),您必须添加 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 的定义,例如能够在编译时使用它来评估 const 表达式。

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

Quentin 的评论 (stolen from Quentin) 中的 link 很好地解释了原因。