【问题标题】:One or more multiply defined symbols found找到一个或多个多重定义的符号
【发布时间】:2011-09-22 03:03:58
【问题描述】:

DebugUtil.h

#ifndef DEBUG_UTIL_H
#define DEBUG_UTIL_H

#include <windows.h>

int DebugMessage(const char* message)
{
    const int MAX_CHARS = 1023;
    static char s_buffer[MAX_CHARS+1];

    return 0;
}

#endif

当我尝试运行它时,我得到了这个错误:

Terrain.obj:错误 LNK2005:“int __cdecl DebugMessage(char const *)" (?DebugMessage@@YAHPBD@Z) 已经 在 Loodus.obj 中定义

Renderer.obj:错误 LNK2005:“int __cdecl DebugMessage(char const *)" (?DebugMessage@@YAHPBD@Z) 已经 在 Loodus.obj 中定义

test.obj:错误 LNK2005:“int __cdecl DebugMessage(char const *)" (?DebugMessage@@YAHPBD@Z) 已经 在 Loodus.obj 中定义

C:\Users\Tiago\Desktop\Loodus Engine\Debug\Loodus Engine.exe:致命 错误 LNK1169:一个或多个相乘 找到定义的符号

但是为什么会这样呢?我在标题中有#ifndef #define 和#endif,所以不应该发生多个定义

【问题讨论】:

标签: c++


【解决方案1】:

将定义(主体)放在 cpp 文件中,仅将声明保留在 h 文件中。包含守卫只在一个翻译单元(也就是源文件)中运行,而不是在你的所有程序中运行。

C++ 标准的单一定义规则规定,程序中使用的每个非内联函数都应出现一个定义。因此,另一种选择是使您的函数内联。

【讨论】:

  • 我也有同样的问题。我的头文件的命名空间中有一些常量值。这是一个数学库,所以我内联了它们,但是常量值呢?
  • @CahitBurakKüçüksütcü:常量变量有内部链接;将它们放在头文件中应该没有问题
  • OMFG 把你的 F-ING PAYPALL 给我我会捐给你这么多钱你 MFKR
【解决方案2】:

使函数内联或在头文件中声明函数并在cpp文件中定义。

inline int DebugMessage(const char* message)
{
    const int MAX_CHARS = 1023;
    static char s_buffer[MAX_CHARS+1];

    return 0;
}

编辑:

正如 Tomalak Geret'kal 的评论所建议的那样,最好使用我的后一个建议而不是我的前一个建议,并将函数的声明移动到 cpp 文件中。

【讨论】:

  • inlineing 是您想要内联函数时需要考虑的事情,而不是因为您不了解发生了什么而用来破解编译器错误的事情。
  • @Tomalak Geret'kal:我同意,但我通常不这样做,但如果它是一个小函数,你将在整个程序中使用它会很方便。跨度>
  • 没关系。但是,您的答案中缺少这些标准。
【解决方案3】:

(假设发布的代码是一个标头,包含在多个 .cpp 文件中)

标头保护不会保护您免受链接时多重定义的影响。不管您是否确保每个翻译单元只出现一次标题,如果您有多个翻译单元,那么这仍然是多个定义。

在源文件中写定义,并且只在标题中写声明

唯一的例外是inline 函数、在class 定义中定义的函数(尽管不推荐这样做!)和函数模板。

【讨论】:

  • 和静态函数,以及匿名命名空间中的函数 :)
  • @Armen:嗯,是的,碰巧他们有内部联系。我想我会继续忽略这些。 :)
  • 确实,我从没说过你不应该:)
【解决方案4】:

这个函数包含在每个翻译单元中,因此您可以获得它的多个定义 - 每个 .obj 文件都包含自己的副本。当需要将它们全部链接在一起时,链接器会正确显示上述错误。

你可以做一些事情:

  1. 将定义移至 .cpp 文件,并仅保留标题中的声明。
  2. 在头文件中的函数周围使用匿名命名空间(但要意识到这是一个 hack - 您仍然会有多个定义,只是没有名称冲突)。
  3. 将其标记为内联(尽管它可能并不总是有效 - 仅当编译器实际选择内联它时)。出于与上述相同的原因,这也是一种 hack。

【讨论】:

    【解决方案5】:

    这只防止在同一个源文件中包含多个;多个源文件#includeing 它仍然会生成DebugMessage() 的多个定义。通常,您不应该将函数放在头文件中,或者将它们设置为static(通常是inline,否则通常没有意义,为同一函数定义多个static)。

    【讨论】:

      【解决方案6】:

      将定义移至 .cpp 文件。

      【讨论】:

        【解决方案7】:

        在 C++ 文件中声明您的函数。由于您在头文件中定义了函数,并且该头文件包含在多个源文件中,因此它会为包含它的每个源文件定义。这就是为什么它被报告为在多个地方定义的原因。

        或者,您可以将其设为内联,以便将代码插入到使用它的任何位置,而不是每次都定义为单独的函数。

        【讨论】:

          【解决方案8】:

          看起来您将 DebugUtil.h 包含在多个翻译单元中,然后将这些对象链接在一起。但是,DebugUtil.h 为 DebugMessage 函数提供了一个定义,因此该定义存在于包含标头的所有翻译单元中。结果,当您链接对象时,链接器正确地抱怨符号是多重定义的。

          更改 DebugUtil.h,使其通过原型声明 DebugMessage,但不提供定义,并将 DebugMessage 的定义放在您将编译并与其他对象链接的 .c 文件中。

          【讨论】:

            【解决方案9】:

            100% 确定您正确包含了 Guards 但仍然出现重新定义错误?

            对于 Visual Studio: 我真的很沮丧,因为我正确地包括了警卫, 才发现问题是视觉工作室。如果您已添加文件 到你的项目,编译器会添加两次文件,即使你有 在你的实现文件和头文件周围包含守卫。

            如果您不专门使用 Visual Studio,并且说...有时使用 code::blocks,您可能只想在检测到 Visual Studio 环境不存在时 #include 文件。

            DebugUtil.h :
            ----------------------
            #ifndef _WIN32
            #include "DebugUtil.c"
            #endif
            ----------------------
            

            如果您同意包含 stdio.h, 你可以少一点 hackish:

            DebugUtil.h :
            ----------------------
            #include <stdio.h>
            #ifdef _MSC_VER
            #include "DebugUtil.c"
            #endif
            ----------------------
            

            参考: 预定义宏,Visual Studio: https://msdn.microsoft.com/en-us/library/b0084kay.aspx

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-09-25
              • 2021-12-23
              相关资源
              最近更新 更多