所以,有人带着一个链接失败的项目来找我,错误是 LNK2005:符号已在对象中定义(使用 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):
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.
您的程序中有多个 myAwesomeFunction
定义,因此您违反了规则。这就是您的代码无法正确链接的原因。
可以从链接器的角度来想。编译完这两个翻译单元后,您就有了两个目标文件。链接器的工作是将目标文件连接在一起以形成最终的可执行文件。因此它会在 main
中看到对 myAwesomeFunction
的调用,并尝试在其中一个目标文件中找到相应的函数定义。但是,有两个 定义。链接器不知道要使用哪一个,所以它就放弃了。
现在让我们看看如果在 something.cpp
中定义 myAwesomeFunction
翻译单元会是什么样子:
修复了
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
的定义。当链接器在 main
中看到对 myAwesomeFunction
的调用时,它确切地知道应该将它链接到哪个函数定义。
关于c++ - 这个LNK2005怎么解释?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15385083/