C ++链接错误,符号重新定义
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C ++链接错误,符号重新定义相关的知识,希望对你有一定的参考价值。
我最近遇到了一个问题。
我有三个文件,A.h,B.cpp,C.cpp:
A.h
#ifndef __A_H__
#define __A_H__
int M()
{
return 1;
}
#endif // __A_H__
B.cpp
#include "A.h"
C.cpp
#include "A.h"
当我通过MSVC编译这三个文件时,出现错误:
C.obj : error LNK2005: "int __cdecl M(void)" (?M@@YAHXZ) already defined in B.obj
很容易理解,众所周知,B.obj有一个名为“ M”的符号,C.obj也有一个“ M”。错误来了。
但是,如果我将M方法更改为包含如下所示的方法M的类:
A.h
#ifndef __A_H__
#define __A_H__
class CA
{
public:
int M()
{
return 1;
}
};
#endif // __A_H__
没有更多错误!!有人可以告诉我发生了什么吗?
如果B.cpp和C.cpp包含A.h,则两者都将以M
的definition进行编译,因此两个目标文件都将包含M
的代码。当链接器收集所有功能时,他看到M
在两个目标文件中定义,并且不知道使用哪个。因此,链接器将引发LNK2005。
如果将函数M
放入类声明中,则编译器会将M
标记/处理为内联函数。该信息被写入目标文件。链接器看到两个目标文件都包含CA::M
的inline版本的定义,因此他假定两者相等,并随机选择这两个定义之一。
如果您写过
class CA {
public:
int M();
};
int CA::M()
{
return 1;
}
这将引起与您的初始版本相同的问题(LNK2005),因为那时CA::M
不再是内联的。
所以您可能会猜到,有两种解决方案可供您选择。如果要内联M
,则将代码更改为
__inline int M()
{
return 1;
}
如果您不关心内联,那么请按标准方式进行操作,并将函数declaration放入头文件中:
extern int M();
并将函数definition放入一个cpp文件中(对于A.h,最好是A.cpp):
int M()
{
return 1;
}
请注意,头文件中实际上并不需要extern
。
另一个用户建议您写
static int M()
{
return 1;
}
我不建议这样做。这意味着编译器将M
放入您的两个目标文件中,并将M
标记为仅在每个目标文件本身中可见的函数。如果链接器发现B.cpp中的函数调用M
,则它将在B.obj和C.obj中找到M
。两者都将M
标记为静态,因此链接器将忽略C.obj中的M
并从B.obj中选择M
。反之亦然,如果C.cpp中的函数调用M
,则链接程序将从C.obj中选择M
。您将最终获得M的多个定义,所有定义都具有相同的实现。这是浪费空间。
请参阅http://faculty.cs.niu.edu/~mcmahon/CS241/c241man/node90.html如何执行ifdef防护。您必须在定义之前以ifndef开头。
编辑:啊,不,您的警卫是错误的,这不是问题。将static放在函数的前面,以使其正常工作。类是不同的,因为它们定义类型。
我不知道它到底是什么,但是如果您不需要一个类,我想编译器会自动将“ extern”键添加到您的函数中,因此您将收到包括标头的错误两次。
您可以将static关键字添加到M()方法,因此在内存中只有该函数的一个副本,并且在编译时没有错误。
顺便说一句:我看到您有#endif,但没有#ifdef或#ifndef,这是复制/粘贴错误吗?
以上是关于C ++链接错误,符号重新定义的主要内容,如果未能解决你的问题,请参考以下文章
C ++ XCODE ld:未找到架构x86_64 clang的符号:错误:链接器命令失败,退出代码为1(使用-v查看调用)