如何避免在头文件中定义的变量出现LNK2005链接器错误?

6

我有3个类似这样的cpp文件

#include "Variables.h"
void AppMain() {
    //Stuff...
}

他们都在内部使用相同的变量,因此它们具有相同的标题,但我会得到类似于以下内容的东西。
1>OnTimer.obj : error LNK2005: "int slider" (?slider@@3HA) already defined in AppMain.obj

为什么会这样呢?


4
请在.h文件中变量声明前加上"extern",并在其中一个.cpp文件中进行定义。考虑使用类来代替。 - Hans Passant
7个回答

16

请记住,#include 大致相当于将被包含的文件剪切并粘贴到包含它的源文件中(这只是一个简单的比喻,但你可以理解这个点)。这意味着如果你有:

int x;  // or "slider" or whatever vars are conflicting

如果在头文件中定义了一个全局变量,并且这个头文件被程序中的三个源文件包含,那么它们都将有一个名为 x 的全局变量定义,这将导致冲突。

你需要做的是将变量定义为 extern,这样 .cpp 文件将会得到声明,然后在其中一个 .cpp 文件中给出实际定义。

在 Variables.h 中:

extern int x;

在 SomeSourceFile.cpp 中

int x;

当然,我建议避免使用全局变量,但如果必须使用它们,这将防止它们发生冲突。


3
由于“int slider”已在另一个文件中定义,因此出现了这种情况。请检查是否具有头文件保护...
#ifndef _VARIABLES_H_
#define _VARIABLES_H_

int slider;

#endif

如果跨越多个翻译单元,并且您确实希望变量不同(即非全局),那么可以在匿名命名空间中声明它们:
namespace {
    int slider;
}

如果您确实希望它们全局,可以考虑使用James的解决方案。

5
头文件保护在这里无济于事,因为cpp文件是分别编译的。 - Greg Hewgill
我提供了一个解决方案。请检查修复后的答案。 - deceleratedcaviar
1
@Mark:使用namespace虽然可以编译通过,但它可能并不会达到你的预期结果。如果你希望在所有源文件中都使用相同的变量(这样一个文件中的改动会在另一个文件中可见),上述解决方案并不能做到。 - Greg Hewgill
如果您想让每个.cpp文件拥有独立的滑块变量,请使用此解决方案;如果您想让所有.cpp文件共享同一滑块变量,请使用下面的extern方法。 - James Michael Hare
是的,我需要使用相同的值...更改了接受的答案。 - Mark Lalor

3
这是因为编译器会单独编译每个 .cpp 文件,为每个文件创建一个 .obj 文件。您的头文件似乎有类似以下内容:
int slider;

当你将这段代码包含在你的三个.cpp文件中时,你会得到三份int slider变量的拷贝,就像你在每个.cpp文件中声明了它一样。连接器会对此抱怨,因为你没有为相同名称提供三个不同的东西。

你可能想要做的是修改你的头文件:

extern int slider;

这告诉编译器在某个地方存在一个名为slider的变量,但可能不在此处,并让链接器来解决。然后,在一个.cpp文件中:

int slider;

将一个实际变量提供给链接器进行链接。


1

发生的情况是,Variables.h 中的每个变量都为各个单独的 c 文件提供了全局范围。当链接器编译所有 c 文件时,它会看到具有相同名称的多个变量。

如果您想使用头文件中的变量作为全局变量,则必须在所有变量前面使用关键字 "extern",并且在主文件中不要使用关键字 extern。

主 c 文件:

int n_MyVar;

其他文件:

extern int n_MyVar;

你可以创建两个文件 Variables.h 和 EVariables.h,或者只在 main.cpp 文件中声明变量。

更好的方法是创建一个 Variables 类,并传递类的引用。


1
我知道这是一个旧的帖子,但我在谷歌搜索结果中第一次看到了它。我通过将变量设置为静态来解决了这个问题。
namespace Vert
{
   static int i;
}

我尝试使用extern关键字,但在我的情况下似乎并没有解决问题。


0

我也遇到了这个错误,尽管我使用外部定义。问题在于在外部定义中也初始化了变量:

ID3D11VertexShader*         g_pVertexShader = nullptr;
...
extern ID3D11VertexShader*  g_pVertexShader = nullptr;  // here's the problem 

=> 错误

ID3D11VertexShader*         g_pVertexShader = nullptr;
...
extern ID3D11VertexShader*  g_pVertexShader;           // without initializing  

=>没有错误,问题已解决


0

如果通过“Variables.h”多次包含变量,则可以通过将其声明为const来避免此链接错误。


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