因此,有人带着一个项目链接失败并出现错误 LNK2005: symbol already defined in object 来找我(使用 Visual Studio 2010)。在这种情况下,我知道出了什么问题(因此可以将他们指向正确的解决方案),但我不知道为什么这在一定程度上是错误的,无法对此做出很好的解释(以防止再次发生)。
// something.h
#ifndef _SOMETHING_H
#define _SOMETHING_H
int myCoolFunction();
int myAwesomeFunction() // Note implementing function in header
{
return 3;
}
#endif
——
// something.cpp
#include "something.h"
int myCoolFunction()
{
return 4;
}
——
// main.cpp
#include <iostream>
#include "something.h"
int main()
{
std::cout << myAwesomeFunction() << std::endl;
}
链接失败,通过将 myAwesomeFunction() 放入 .cpp 并在 .h 中留下声明来修复。
我对链接器如何工作的理解几乎来自 here 。据我了解,我们在一个地方提供了一个必需的符号。
我查找了 MSDN article on LNK2005 ,它符合我期望链接器的行为方式(多次提供符号-> 链接器被混淆),但似乎没有涵盖这种情况(这意味着我不了解链接的一些明显内容) .
Google 和 StackOverflow 会产生不包含
#ifndef
或 #pragma once
的人的问题(这会导致提供的符号有多个声明)A related question I found on this site 也有同样的问题,但答案并没有解释为什么我们在我的理解水平上充分解决了这个问题。
我有问题,我知道解决方案,但我不知道为什么我的解决方案有效
最佳答案
在典型的 C++ 项目中,您分别编译每个实现(或 .cpp
)文件 - 通常不会将头(或 .h
)文件直接传递给编译器。在执行所有预处理和包含之后,这些文件中的每一个都成为一个翻译单元。因此,在您给出的示例中,有两个翻译单元如下所示:
main.cpp
翻译单元:// Contents of <iostream> header here
int myCoolFunction();
int myAwesomeFunction() // Note implementing function in header
{
return 3;
}
int main()
{
std::cout << myAwesomeFunction() << std::endl;
}
something.cpp
翻译单元:int myCoolFunction();
int myAwesomeFunction() // Note implementing function in header
{
return 3;
}
int myCoolFunction()
{
return 4;
}
请注意,这两个翻译单元都包含重复的内容,因为它们都包含
something.h
。如您所见,上述翻译单元中只有一个包含 myCoolFunction
的定义。那挺好的!但是,它们都包含 myAwesomeFunction
的定义。那很糟!翻译单元分别编译后,再链接起来形成最终程序。关于跨翻译单元的多个声明有一定的规则。其中一项规则是(第 3.2/4 节):
您的程序中有多个
myAwesomeFunction
定义,因此您违反了规则。这就是您的代码无法正确链接的原因。您可以从链接器的角度考虑。编译这两个翻译单元后,您有两个目标文件。链接器的工作是将目标文件连接在一起以形成最终的可执行文件。因此,它在
myAwesomeFunction
中看到对 main
的调用,并尝试在目标文件之一中找到相应的函数定义。但是,有两个定义。链接器不知道使用哪一个,所以它就放弃了。现在让我们看看在
myAwesomeFunction
中定义 something.cpp
时翻译单元的样子:main.cpp
翻译单元:// Contents of <iostream> header here
int myCoolFunction();
int myAwesomeFunction();
int main()
{
std::cout << myAwesomeFunction() << std::endl;
}
something.cpp
翻译单元:int myCoolFunction();
int myAwesomeFunction();
int myCoolFunction()
{
return 4;
}
int myAwesomeFunction()
{
return 3;
}
现在它很完美。现在整个程序只有一个
myAwesomeFunction
的定义。当链接器在 myAwesomeFunction
中看到对 main
的调用时,它确切地知道应该将它链接到哪个函数定义。关于c++ - 我如何解释这个 LNK2005?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15385083/