我最近遇到了一个问题。
我有三个文件,Ah,B.cpp和C.cpp:
啊
#ifndef __A_H__
#define __A_H__
int M()
{
return 1;
}
#endif // __A_H__
Run Code Online (Sandbox Code Playgroud)
丙型肝炎
#include "A.h"
Run Code Online (Sandbox Code Playgroud)
丙型肝炎
#include "A.h"
Run Code Online (Sandbox Code Playgroud)
当我通过MSVC编译这三个文件时,出现一个错误:
C.obj : error LNK2005: "int __cdecl M(void)" (?M@@YAHXZ) already defined in B.obj
Run Code Online (Sandbox Code Playgroud)
众所周知,B.obj有一个名为“ M”的符号,C.obj也有一个“ M”。错误来了。
但是,如果我将M方法更改为包含如下所示的方法M的类:
啊
#ifndef __A_H__
#define __A_H__
class CA
{
public:
int M()
{
return 1;
}
};
#endif // __A_H__
Run Code Online (Sandbox Code Playgroud)
没有更多的错误!有人可以告诉我发生了什么吗?
如果B.cpp和C.cpp包括啊,那么两者都编译你定义的M
,所以这两个目标文件将包含的代码M
。当链接器收集所有功能时,他看到M
在两个目标文件中定义了该功能,并且不知道要使用哪个功能。因此,链接器引发了LNK2005。
如果将函数M
放入类声明中,则编译器将标记/处理M
为内联函数。该信息被写入目标文件。链接器看到两个目标文件都包含的内联版本的定义CA::M
,因此他假定两者都相等,并随机选择这两个定义之一。
如果你写过
class CA {
public:
int M();
};
int CA::M()
{
return 1;
}
Run Code Online (Sandbox Code Playgroud)
这会引起与您的初始版本相同的问题(LNK2005),因为那样CA::M
就不会再进行内联了。
因此,您可能已经猜到了,有两种解决方案可供您选择。如果要M
内联,则将代码更改为
__inline int M()
{
return 1;
}
Run Code Online (Sandbox Code Playgroud)
如果您不关心内联,那么请以标准方式进行,然后将函数声明放入头文件中:
extern int M();
Run Code Online (Sandbox Code Playgroud)
并将函数定义放入cpp文件中(对于Ah,理想情况下,它将是A.cpp):
int M()
{
return 1;
}
Run Code Online (Sandbox Code Playgroud)
请注意,extern
头文件中的并不是必需的。
另一个用户建议您写
static int M()
{
return 1;
}
Run Code Online (Sandbox Code Playgroud)
我不建议这样做。这意味着编译器将同时M
放入您的目标文件并将其标记M
为仅在每个目标文件本身中可见的函数。如果链接器发现B.cpp中的函数正在调用M
,它将M
在B.obj和C.obj中找到。两者都M
标记为静态,因此链接器M
在C.obj中忽略并M
从B.obj中选择。反之亦然,如果C.cpp中的函数调用M
,则链接器M
将从C.obj中选择。您将最终获得M的多个定义,所有定义都具有相同的实现。这是浪费空间。
归档时间: |
|
查看次数: |
1745 次 |
最近记录: |