变量已在 .obj 中定义;这是怎么回事?

Variable already defined in .obj; What is going on here?

本文关键字:怎么回事 定义 obj 变量      更新时间:2023-10-16

head.h


#pragma once
namespace foo
{
int bar;
int funct1();
}

头.cpp

#include "head.h"
int foo::funct1()
{
return bar;
}

主.cpp

#include <iostream>
#include "head.h"

int main()
{
foo::bar = 1;
std::cout << foo::funct1() << std::endl;
return 0;
}

错误LNK2005 "int foo::bar" (?bar@foo@@3HA) 已在 head.obj 中定义

我不明白发生了什么。我试图寻找答案,但每个人的问题都非常特定于他们的代码,甚至看起来都与我遇到的问题不符。

我没有将.cpp文件包含在 main 中。我不是在重新定义任何东西。从字面上看,我只是将 1 分配给变量,然后用同一命名空间中的函数返回它。它是如何被多次定义的?

标头head.h包含在两个编译单元head.cppmain.cpp中。因此,变量bar被定义两次。您可以通过以下方式声明变量而不定义其

#pragma once
namespace foo
{
extern int bar;
int funct1();
}

然后在某个 cpp 模块中定义它。

foo命名空间级别的bar声明:

namespace foo
{
int bar;
}

实际上是一个定义

要使其成为声明,请在head.h中将bar标记为extern

namespace foo
{
extern int bar;
}

然后在 head 中定义它.cpp

int foo::bar = 0;
head.h

包含在main.cpp和head.cpp中。 因此,变量被定义了两次。

可能的解决方案:使其内联。"外部"解决方案也很好,尽管方法较老。

namespace foo
{
inline int bar;
}

它是如何被多次定义的?

它在头部定义一次.cpp在主.cpp中定义一次。这总共是两次。这违反了一个定义规则,该规则指出每个变量可能只有一个定义。

int bar;

这是变量的定义。您已将其包含在两个翻译单元中。

变量可以在 extern 声明中无需定义即可声明:

extern int bar;

将定义替换为此类声明,并将定义恰好放入一个翻译单元中。

我不是在重新定义任何东西。我实际上只是将 1 分配给变量

您正在重新定义变量!

head.cpp有一个通孔#include "head.h"main.cpp有一个通孔#include "head.h"

您只需要在标头中声明它(不寻常但不太奇怪):

extern int bar;

然后在一个翻译单元中定义它。这就像您对static类成员所做的那样(尽管语法略有不同)。

从 C++17 开始,您可以通过将inline关键字添加到您的定义中来执行此操作。

或者,避免可变全局变量...

请注意foo不是一个类,而是一个命名空间。在头文件中声明自由变量时:

int bar;

然后多次 #include 此头文件(放入不同的 CPP 文件中,导致多个翻译单元编译),会出现链接器错误。每个人都知道这一点。

而且,您将在声明中添加extern属性,并在其中一个 CPP/C 文件中的其他位置定义变量。

将全局变量放入命名空间无非是给全局变量一个不同的名称。想想如果foo::barfoo__NS__bar,因此您必须在标题中添加extern并在某个位置定义foo::bar

请注意,这与类的非静态成员变量不同。类变量不需要以这种方式定义/声明,因为类是一种类型。类类型的每个实例化变量都有一个单独的变量副本。 此外,当您在类中添加static变量时,您将为该逻辑全局变量指定另一个名称。然后,您必须为该静态变量定义一个 CPP 文件。