2011-06-24 13 views
33

DebugUtil.hJeden lub więcej mnożyć zdefiniowane symbole znaleźć

#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 

Kiedy próbuję uruchomić to uzyskać ten błąd:

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

Ale dlaczego tak się dzieje? Mam #ifndef #define i #endif w nagłówku, więc wiele definicji nie powinno się zdarzyć

+0

możliwym duplikat [Błąd linku z naprawdę prostymi funkcjami C++ na pliku .h] (http://stackoverflow.com/questions/6424911/link-error-with-really-simple-functions-c-on-h-file) –

+0

@ Armen: To jest jak Hame, że odpowiedzi na to pytanie są znacznie lepsze :( –

Odpowiedz

54

Umieść definicję (treść) w pliku cpp i pozostaw tylko deklarację w pliku h. Uwzględnij osłony działają tylko w jednej jednostce tłumaczeniowej (aka pliku źródłowego), a nie we wszystkich programach.

Reguła jednej definicji standardu C++ stwierdza, że ​​powinna pojawić się dokładnie jedna definicja każdej nieinsertacyjnej funkcji używanej w programie. Inną alternatywą byłoby wprowadzenie funkcji w linii.

+2

Mam ten sam problem. Mam pewne stałe wartości w przestrzeni nazw w moim pliku nagłówkowym. To jest biblioteka matematyczna, więc je opisałem, ale co z wartościami stałymi? –

+0

@ CahitBurakKüçüksütcü: zmienne stałe mają powiązania wewnętrzne; nie powinno być problemu z ich zapisaniem w pliku nagłówkowym –

+0

OMFG DAJ MI SWOJE F-ING PAYPALL ILL PRZEKAŻ CIEBIE TWOJE PIENIĄDZE MFKR – Acidic

10

Wprowadź funkcję w linii lub zadeklaruj funkcję w pliku nagłówkowym i zdefiniuj ją w pliku cpp.

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

    return 0; 
} 

EDIT:

jako komentarz przez Tomalak Geret'kal sugeruje, że lepiej wykorzystać te ostatnie moje sugestie niż mój dawny i przenieść deklarację funkcję do pliku cpp.

+2

'inline'ing jest czymś, o czym należy pomyśleć, gdy chcesz wstawić funkcję, a nie coś użyj do zhakowania błędów kompilatora, ponieważ nie wiesz, co się dzieje. –

+0

@ Tomalak Geret'kal: Zgadzam się, że tak jest i zwykle tego nie robię, ale może to być wygodne, jeśli jest to mała funkcja, z której będziesz korzystać w całym programie. – GWW

+0

I to dobrze. W twojej odpowiedzi brakowało takich kryteriów. –

0

Przenieś definicję do pliku .cpp.

0

Zadeklaruj swoje funkcje w plikach C++. Ponieważ zdefiniowałeś swoją funkcję w pliku nagłówkowym, a ten plik nagłówkowy jest zawarty w wielu plikach źródłowych, zostaje on zdefiniowany dla każdego pliku źródłowego, który go zawiera. Dlatego jest zgłaszane jako zdefiniowane w wielu miejscach.

Można również wstawić go tak, aby kod był wstawiany wszędzie tam, gdzie jest używany, a nie za każdym razem definiowany jako osobna funkcja.

0

Wygląda na to, że włączasz DebugUtil.h do więcej niż jednej jednostki tłumaczeniowej, a następnie łączysz te obiekty razem. Jednak DebugUtil.h zapewnia definicję funkcji DebugMessage, więc definicja istnieje we wszystkich jednostkach tłumaczeniowych, które włączyły nagłówek. W rezultacie, gdy łączysz obiekty, linker słusznie narzeka, że ​​symbol jest wielokrotnie definiowany.

Zmień DebugUleil.h, aby zadeklarował DebugMessage za pośrednictwem prototypu, ale nie zapewnia definicji, i umieść definicję DebugMessage w pliku .c, który skompilujesz i połączysz z innymi obiektami.

0

To tylko zapobiega wielokrotnym inkluzjom w tym samym pliku źródłowym; wiele plików źródłowych #include będzie nadal generować wiele definicji DebugMessage(). Zasadniczo nie należy umieszczać żadnych funkcji w plikach nagłówkowych ani tworzyć ich static (i zwykle inline, ponieważ w przeciwnym razie zwykle nie ma sensu posiadanie wielu definicji static tej samej funkcji).

3

Ta funkcja jest zawarta w każdej jednostce tłumaczeniowej iw rezultacie otrzymujesz wiele jej definicji - każdy plik .obj zawiera swoją własną kopię. Kiedy nadszedł czas, aby połączyć je wszystkie razem linker słusznie pokazuje powyższy błąd.

można zrobić kilka rzeczy:

  1. przeniesienie definicji w pliku .cpp i zachować tylko oświadczenie w nagłówku.
  2. Użyj anonimowego obszaru nazw wokół funkcji w pliku nagłówkowym (ale uświadom sobie, że to hack - nadal będziesz mieć wiele definicji, po prostu nie kolizję nazw).
  3. Oznacz to jako wbudowane (chociaż może nie zawsze działać - tylko wtedy, gdy kompilator faktycznie zdecyduje się na wstawienie go). To także włamanie z tego samego powodu, co powyżej.
5

(Zakładając oddelegowanego kod jest nagłówek, zawarte z wielu plików .cpp)

strażnicy Header nie chroni cię od łącza czasowych wielu definicji. Bez względu na to, że zapewniłeś, że nagłówek pojawi się tylko raz na jednostkę tłumaczenia, jeśli masz więcej niż jedną jednostkę tłumaczeń, to nadal jest to wiele definicji.

Zapisywanie definicji w plikach źródłowych i tylko deklaracji w nagłówkach.

Jedynymi wyjątkami są funkcje inline, funkcje zdefiniowane w definicji class (choć nie jest to zalecane!) I szablony funkcji.

+0

oraz funkcje statyczne i funkcje w anonimowych przestrzeniach nazw :) –

+0

@Armen: Cóż, tak, przez przypadek, że mają wewnętrzne powiązania. Myślę, że będę je ignorował. :) –

+0

Rzeczywiście, nigdy nie powiedziałem, że nie powinieneś :) –

0

100% Pewne twoje entuzjastyczne gaurd są poprawne, ale wciąż dostajesz błąd redefinicji?

Visual Studio: Byłem naprawdę frusterated bo robił to mój gaurds poprawnie, tylko dowiedzieć się, problem był visual studio. Jeśli dodałeś plik do swojego projektu, kompilator doda ten plik dwa razy, nawet jeśli posiadasz to gaurds wokół pliku implementacji i pliku nagłówkowego.

Jeśli nie korzystasz wyłącznie ze studia graficznego i powinieneś ... używać czasami kodów :: blocks, możesz chcieć włączyć tylko plik, gdy wykryjesz brak środowiska graficznego.

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

Jeśli są w porządku z tym stdio.h, można być trochę mniej hackish o tym:

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

referencyjny: predefiniowanych makr Visual Studio: https://msdn.microsoft.com/en-us/library/b0084kay.aspx

Powiązane problemy