gpt4 book ai didi

visual-c++ - C++链接错误,符号重定义

转载 作者:行者123 更新时间:2023-12-01 22:40:07 24 4
gpt4 key购买 nike

我最近遇到了一个问题。

我有三个文件,A.h、B.cpp、C.cpp:

啊啊

#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 的类:

啊啊

#ifndef __A_H__
#define __A_H__

class CA
{
public:
int M()
{
return 1;
}
};

#endif // __A_H__

没有错误了!!有人能告诉我发生了什么事吗?

最佳答案

如果 B.cpp 和 C.cpp 包含 A.h,那么它们都将使用 M定义进行编译,因此两个目标文件都将包含 M 的代码。当链接器收集所有函数时,他看到 M 定义在两个目标文件中,但不知道该使用哪一个。因此,链接器引发 LNK2005。

如果您将函数M 放入类声明 中,则编译器会将M 标记/处理为内联函数。此信息被写入对象文件。链接器发现这两个目标文件都包含 内联 版本的 CA::M 的定义,因此他假设两者相等并随机选择两个定义之一.

如果你写过

class CA {
public:
int M();
};

int CA::M()
{
return 1;
}

这会导致与您的初始版本相同的问题 (LNK2005),因为那时 CA::M 将不再是内联的。

您现在可能已经猜到了,有两种解决方案适合您。如果您希望内联 M,则将您的代码更改为

__inline int M()
{
return 1;
}

如果您不关心内联,那么请按照标准方式进行,并将函数声明放入头文件中:

extern int M();

然后将函数定义放入一个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 的多个定义,所有这些定义都具有相同的实现。这是对空间的浪费。

关于visual-c++ - C++链接错误,符号重定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15941756/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com