2011-06-24 118 views
33

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 : error LNK2005: "int __cdecl DebugMessage(char const *)" ([email protected]@[email protected]) already defined in Loodus.obj

Renderer.obj : error LNK2005: "int __cdecl DebugMessage(char const *)" ([email protected]@[email protected]) already defined in Loodus.obj

test.obj : error LNK2005: "int __cdecl DebugMessage(char const *)" ([email protected]@[email protected]) already defined in Loodus.obj

C:\Users\Tiago\Desktop\Loodus Engine\Debug\Loodus Engine.exe : fatal error LNK1169: one or more multiply defined symbols found

但是,爲什麼會發生這種情況?我在頭文件中有#ifndef #define和#endif,所以應該不會發生多個定義

+0

可能[鏈接錯誤與真正簡單的函數C++上.h文件]的副本(http://stackoverflow.com/questions/6424911/link-error-with-really-simple-functions-c-on-h-file) –

+0

@ Armen:這是哈姆在_this_問題上的答案好多了:( –

回答

54

將定義(body)放入cpp文件中,並且只將聲明留在h文件中。包括警衛只能在一個翻譯單元(又名源文件)中運行,而不是跨越所有程序。

C++標準的一個定義規則規定,應該在程序中使用每個非內聯函數的一個定義。所以,另一種選擇是讓你的函數內聯。

+2

我有同樣的問題。我的頭文件中的名稱空間中有一些常量值。這是一個數學庫,所以我將它們插入其中,但恆定值又如何呢? –

+0

@CahitBurakKüçüksütcü:常量變量有內部聯繫;應該沒有問題讓他們在頭文件 –

+0

OMFG給我你的F-ING PAYPALL ILL給你這麼多錢你MFKR – Acidic

10

使函數內聯或在頭文件中聲明函數並將其定義在cpp文件中。

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

    return 0; 
} 

編輯:

正如託默勒格Geret'kal一個意見建議,最好使用我的建議,後者比我前和移動函數的聲明到CPP文件。

+2

'內嵌'是當你想要內聯函數時要考慮的事情,而不是你用來繞過編譯器錯誤,因爲你不明白髮生了什麼。 –

+0

@Tomalak Geret'kal:我同意這是我通常不會這樣做的,但如果它是一個小函數,您將在整個程序中使用它,那麼它可能會很方便。 – GWW

+0

這很好。雖然這樣的標準從你的答案中遺漏了。 –

0

將定義移動到.cpp文件。

0

在C++文件中聲明你的函數。由於您在頭文件中定義了函數,並且該頭文件包含在多個源文件中,因此將爲包含它的每個源文件定義它。這就是爲什麼它被報告定義在多個地方。

或者,您可以使其內聯,以便在每次使用代碼時插入代碼,而不是每次都將其定義爲單獨的函數。

0

它看起來像是在多個翻譯單元中包含DebugUtil.h,然後將這些對象鏈接在一起。但是,DebugUtil.h爲DebugMessage函數提供了一個定義,所以定義存在於所有包含頭文件的翻譯單元中。因此,鏈接對象時,鏈接器會正確地抱怨該符號被多次定義。

更改DebugUtil.h,使其通過原型聲明DebugMessage,但不提供定義,並將DebugMessage的定義放置到.c文件中,您將編譯並鏈接到其他對象。

0

這隻能防止在同一個源文件中的多個包含;多個源文件#include仍然會生成DebugMessage()的多個定義。一般來說,你不應該在頭文件中放置函數,或者使它們成爲static(通常是inline,因爲否則通常沒有多個定義同一函數的static)。

3

該功能包含在每個翻譯單元中,因此您可以獲得多個定義 - 每個.obj文件都包含自己的副本。當它們連接在一起時,鏈接器正確地顯示上述錯誤。

你可以做幾件事情:

  1. 移動的定義.cpp文件,只保留聲明,在頭中。
  2. 在頭文件中的函數週圍使用匿名命名空間(但意識到這是一個黑客 - 你仍然有多個定義,只是沒有名稱衝突)。
  3. 將其標記爲內聯(儘管它可能無法正常工作 - 只有在編譯器實際選擇將其內聯時)。這也是與上述相同的原因。
5

(假設發佈的代碼是一個標題,從多個.cpp文件包括)

頁眉警衛不保護你的鏈接時多個定義。無論您是否確保每個翻譯單元僅出現一次標題,如果您有多個翻譯單元,那麼仍然有多個定義。

在源文件中寫入定義,並且只在標頭中寫入聲明

唯一的例外是inline函數,定義在class定義(儘管這不推薦!)和函數模板中定義的函數。

+0

和靜態函數,以及匿名命名空間中的函數:) –

+0

@Armen:好的,是的,偶然,他們有內部聯繫。我想我會繼續忽略這些。 :) –

+0

的確,我從來沒有說過你不應該:) –

0

100%確定您的高爾夫球是正確的,但仍然會出現重新定義錯誤?

對於Visual Studio: 我真的frusterated,因爲我在做我的正確包括gaurds, 才發現出了問題是視覺工作室。如果您已將文件 添加到您的項目中,即使您的執行文件和頭文件包含gaurds,編譯器也會將文件添加兩次。

如果您沒有專門使用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

相關問題