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

5
我有一个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”的可执行文件,但是出现了错误。我看不出它应该失败的任何原因。

a.cpp 需要包含 a.h 吗? - NathanOliver
1
我认为这与C++中常量具有内部链接有关。 - Rob K
@Haatschii 我的字符串会不会在最终的二进制文件中出现两次? - Maya
2
请参阅https://dev59.com/H3NA5IYBdhLWcg3wWsYA。 - Quentin
@NathanOliver 检查过了,它编译通过了。但我仍然不明白为什么要包含它(定义也是声明)。 - Maya
2个回答

7

作为一个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表达式。


0
最简单的解决方法是在你的定义中添加关键字extern。我知道看起来很奇怪,extern通常会变成一个前向声明而不是一个定义,但是编译器会仍然将其视为定义(实例化),因为你给它一个值。
Quentin评论中的链接 (从Quentin那里偷的) 是一个非常好的解释。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接