如果希望两者引用同一个变量,则其中一个应该具有int k;,另一个应该具有extern int k; 对于这种情况,通常将定义(int k;)放在一个.cpp文件中,并将声明(extern int k;)放在头文件中,以便在需要访问该变量的任何地方都包含该文件。 如果你希望每个k都是一个单独的变量,只是碰巧有相同的名字,你可以将它们标记为static,比如:static int k;(在所有文件中,或者至少除了一个文件之外的所有文件中)。或者,你可以使用一个匿名命名空间:
namespace {
int k;
};
字符串 同样,除了最多一个文件。 在C中,编译器通常对此并不那么挑剔。具体来说,C有一个“临时定义”的概念,所以如果你有两次像int k;这样的东西,(在相同或单独的源文件中)每一个都将被视为一个临时定义,它们之间不会有冲突。然而,这可能有点令人困惑,因为你仍然不能有两个都包含初始化器的定义--一个包含初始化器的定义总是一个完整的定义,而不是一个临时的定义。换句话说,int k = 1;出现两次是一个错误,但是在一个地方的int k;和在另一个地方的int k = 1;不会。在这种情况下,int k;将被视为临时定义,而int k = 1;将被视为定义(并且两者引用相同的变量)。
template<typename x_Dummy = void> class
t_HeaderVariableHolder
{
public: static int s_k;
};
template<typename x_Dummy> int t_HeaderVariableHolder<x_Dummy>::s_k{};
// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
return t_HeaderVariableHolder<>::s_k;
}
字符串 使用C++17,事情变得简单得多,因为它允许inline变量:
inline int g_k{};
// Getter is necessary to decouple variable storage implementation details from access to it.
inline int & Get_K() noexcept
{
return g_k;
}
9条答案
按热度按时间rta7y2nd1#
为什么会出现这个错误?
你破坏了**one definition rule**,因此导致了链接错误。
建议解决方案:
如果您需要在两个cpp文件中使用相同的命名变量,则需要使用Nameless namespace(匿名命名空间)来避免错误。
字符串
如果你需要在多个文件中共享同一个变量,那么你需要使用
extern
。A.h
型
A.cpp
型
B.cpp**
型
368yc8dk2#
在项目的设置中,将
/FORCE:MULTIPLE
添加到链接器的命令行选项中。来自MSDN:“使用/FORCE:MULTIPLE创建输出文件,无论LINK是否为符号找到多个定义。”
plupiseo3#
如果希望两者引用同一个变量,则其中一个应该具有
int k;
,另一个应该具有extern int k;
对于这种情况,通常将定义(
int k;
)放在一个.cpp
文件中,并将声明(extern int k;
)放在头文件中,以便在需要访问该变量的任何地方都包含该文件。如果你希望每个
k
都是一个单独的变量,只是碰巧有相同的名字,你可以将它们标记为static
,比如:static int k;
(在所有文件中,或者至少除了一个文件之外的所有文件中)。或者,你可以使用一个匿名命名空间:字符串
同样,除了最多一个文件。
在C中,编译器通常对此并不那么挑剔。具体来说,C有一个“临时定义”的概念,所以如果你有两次像
int k;
这样的东西,(在相同或单独的源文件中)每一个都将被视为一个临时定义,它们之间不会有冲突。然而,这可能有点令人困惑,因为你仍然不能有两个都包含初始化器的定义--一个包含初始化器的定义总是一个完整的定义,而不是一个临时的定义。换句话说,int k = 1;
出现两次是一个错误,但是在一个地方的int k;
和在另一个地方的int k = 1;
不会。在这种情况下,int k;
将被视为临时定义,而int k = 1;
将被视为定义(并且两者引用相同的变量)。u2nhd7ah4#
假设您希望“k”在不同的.cpp文件中是不同的值(因此声明了两次),请尝试将两个文件都更改为
字符串
这保证了名称“k”在翻译单元中唯一标识“k”。旧版本
static int k;
已弃用。如果你想让它们指向相同的值,可以将其中一个改为
extern int k;
。hjzp0vay5#
这两个文件都将变量
k
定义为整数(int
)。因此,链接器会看到两个同名的变量,并且不确定如果引用
k
时应该使用哪一个。要解决这个问题,请将其中 one 声明更改为:
字符串
这意味着:*“k是一个整数,在这里声明,但在外部定义(即另一个文件)。
现在只有一个变量
k
,可以被两个不同的文件引用。s4chpxco6#
如果你想让这些翻译单元共享这个变量,在A.cpp中定义
int k;
,并把extern int k;
放在B.cpp中。ryoqjall7#
头文件中存在
int k;
会导致符号k
在包含此头文件的每个转换单元中定义,而链接器希望它只定义一次(也称为一个定义规则违规)。虽然涉及
extern
的建议没有错,但extern
是C主义,不应该使用。在C++17之前,允许在多个翻译单元中定义头文件中的变量而不会导致ODR冲突的解决方案是转换为模板:
字符串
使用C++17,事情变得简单得多,因为它允许
inline
变量:型
erhoui1w8#
链接器告诉您已经多次定义了变量
k
,您在A.cpp中有一个定义,在B.cpp中有另一个定义。这两个编译单位都会产生链接器用来建立程式的Map目的档。问题是,在您的案例中,链接器不知道要使用k
的哪一个定义。在C++中同一个构造(变量、类型、函数)只能有一个定义。要解决这个问题,你必须决定你的目标是什么
k
,您可以在两个.cpp档案中使用匿名命名空间,然后参照k
,就像您现在所做的一样:。
字符串
k
重命名为其他名称,从而避免重复的定义。k
的定义,并在两个.cpp文件中使用它,你需要在一个文件中声明为extern int k;
,并在另一个文件中保持不变。这将告诉链接器在两种情况下都使用一个定义(未更改的版本)--extern
意味着变量是在另一个编译单元中定义的。23c0lvtd9#
正如之前在社区中提到的,这基本上是由在头文件中实现定义并在项目中多次包含它引起的。为了解决这个问题,我在变量和函数/方法的定义之前使用了内联,它工作得很好。
字符串