LNK2005



  • Hallo, ich habe eine Frage zum Linker-Fehler LNK2005. Ich konnte mein Projekt nun auf diese vier Dateien hier reduzieren um den Fehler zu reproduzieren:

    main.cpp

    #include <iostream>
    #include "func.hpp"
    #include "replacement.hpp"
    
    int main()
    {
    	std::cout << foo().func(5) << '\n' << Abs(0);
    }
    

    replacement.hpp

    #ifndef replacement_hpp_included
    #define replacement_hpp_included
    
    #include <cstdlib>
    
    int Abs(int x)
    {
    	return std::abs(x);
    }
    
    #endif // replacement_hpp_included
    

    func.hpp

    #ifndef func_hpp_included
    #define func_hpp_included
    
    struct foo
    {
    	int func(int x) const;
    };
    
    #endif // func_hpp_included
    

    func.cpp

    #include "func.hpp"
    #include "replacement.hpp"
    
    int foo::func(int x) const
    {
    	return Abs(x);
    }
    

    Ausgabe:

    1>------ Erstellen gestartet: Projekt: Projekt1, Konfiguration: Debug x64 ------
    1>  main.cpp
    1>main.obj : error LNK2005: "int __cdecl Abs(int)" (?Abs@@YAHH@Z) ist bereits in func.obj definiert.
    1>C:\Users\gehteuchnixan!\Desktop\Projekt1\x64\Debug\Projekt1.exe : fatal error LNK1169: Mindestens ein mehrfach definiertes Symbol gefunden.
    ========== Erstellen: 0 erfolgreich, 1 fehlerhaft, 0 aktuell, 0 übersprungen ==========
    

    Mein Compiler ist der neue MSVC Community 2015 😋 falls das eine Rolle spielt. Ich verstehe den Fehler insofern nicht, weil die Definition von Abs in allen Übersetzungseinheiten eigentlich äquivalent ist.

    Grüßle



  • Du verletzt dir One Definition Rule: die Funktion ist in jedem cpp definiert, das den Header einbindet. Genau das sagt die Fehlermeldung. Wenn du eine Funktion im Header definieren willst, musst du inline verwenden.



  • Du hast eine Funktion im Header definiert. Das sorgt für mehrfach definierte Symbole wenn der Header in mehr als einer *.cpp Datei eingebunden ist. Die übliche Variante ist im Header nur die Deklaration zu haben und die Implementation dann in der gleichnamigen *.cpp Datei. Wenn man die Funktion unbedingt im Header haben möchte kann man die Funktion auch mit inline markieren. Bei so kurzen Funktionen wie jetzt in deinem Beispiel ist das sogar sinnvoll. Inline Funktionen sind von der One Definition Rule ausgenommen.



  • Das Problem ist, dass replacement.hpp normalerweise viele viele Header sind, die ihre Funktionen usw. alle im Header selbst definiert haben. Muss ich zum Lösen des Problems alle Header durchgehen und alle nicht- template -Funktionen und Methoden inline definieren?



  • Leider Ja. Übrigens sind neben template Funktionen auch Memberfunktionen die direkt in der Klasse definiert sind automatisch inline. Also etwas wie:

    class MyClass
    {
    public:
      void someStuff() // ist automatisch inline
      {
        // do whatever
      }
    };
    


  • So scheint es zu funktionieren. Irgendwie glaubte ich, dass Definitionen im Header auch implizit inline sind 😕 ... Danke fürs Aufklären



  • Und was muss ich machen wenn in den Headerfiles globale Variablen oder static Member definiert werden? 😞
    Die Bibliothek sollte Header-only bleiben aber ich weiß nicht, wie ich diese doofen Linkerfehler wegkriege.



  • Wenn die globale Variable konstant ist dann schreib ein const dran. Wenn nicht wüsste ich nicht wie man das Header only hinkriegt. Da musst du wohl ohne globale Variable leben oder weg von Header only.



  • Und bei nichtintegralen static const Membern?
    Die Sache ist die: Die Bibliothek besteht zu 95% aus Templates und den Rest hab ich nun inline gemacht. Von den 4800+ Linkerfehlern bin ich jetzt auf 136 gekommen, die alle nur noch auf static const Member zurückzuführen sind. Die eine globale Variable hätte eigentlich const sein müssen, war ein Bug, dass es nicht so war! Für die extern e Definition dieser paar Membern die Header-only-Vorzüge aufzugeben möchte ich nur sehr ungern.



  • Probier mal constexpr führ float aus.


Anmelden zum Antworten