找到一个或多个多重定义的符号

时间:2011-06-24 15:14:49

标签: c++

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:\用户\蒂亚戈\桌面\ Loodus   Engine \ Debug \ Loodus Engine.exe:致命   错误LNK1169:一次或多次乘法   找到已定义的符号

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

9 个答案:

答案 0 :(得分:61)

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

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

答案 1 :(得分:9)

使函数内联或在头文件中声明函数并在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文件中。

答案 2 :(得分:6)

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

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

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

唯一的例外是inline函数,在class定义中定义的函数(虽然不建议这样做!)和函数模板。

答案 3 :(得分:3)

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

你可以做一些事情:

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

答案 4 :(得分:0)

将定义移动到.cpp文件。

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

这只能防止同一源文件中出现多个包含内容;多个源文件#include仍将生成DebugMessage()的多个定义。一般情况下,您应该根本不将函数放在头文件中,或者将它们设为static(通常是inline,否则通常不会有多个static定义相同的功能)。

答案 8 :(得分:0)

100%确定您是否正确包含了警卫,但仍然出现重新定义错误?

对于Visual Studio: 我真的很沮丧,因为我被正确包括在内, 只是找出问题是视觉工作室。如果您已添加该文件 对于您的项目,编译器将添加文件两次,即使您有 包括实施文件和头文件的保护。

如果你不单独使用visual studio,并说...有时使用code :: blocks,你可能只想在检测到缺少visual studio环境时#include文件。

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

如果你可以包括stdio.h, 你可以对它不那么讨厌:

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

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