"error LNK2005: already defined" trotz Mehrfach-Include-Sperre?



  • Die Include-Guards helfen nur dagegen, daß der Header in einer Übersetzungseinheit mehrfach verwendet wird. Dein Linker-Problem kommt davon, daß du deinen Header mit den Definitionen in mehreren (unabhängig voneinander übersetzten) Quelldateien verwendet wird - und jede eine eigene Definition anlegt.

    Die Lösung dafür besteht darin, im Header nur Funktions-Prototypen und extern deklarierte Variablen zu verwenden - die tatsächlichen Definitionen stehen in genau einer Quelldatei.
    (Ausnahme sind Templates, aber das ist eine andere Geschichte)



  • 😞 C++-Code gehört in .cpp- und in .hpp-Dateien! Können wir das mal in die FAQ bringen?



  • bei Funktionen habe ich das so gemeint, das nur folgendes da steht: z.B. "void Function();"
    Das der code dazu in eine cpp gehört weis ich...
    Die Variablen extern zu deklarieren, es reicht nämlich nicht einfach ein extern davor zu setzen...



  • Neokil schrieb:

    Die Variablen extern zu deklarieren, reicht es da wenn ich extern vorne dran setzt?

    Fast - in den Header stellst du die Deklaration ala extern int MyState; und in einer CPP-Datei landet die zugehörige Definition int MyState; . Ohne letzteres bekommst du wieder einen anderen Linker-Fehler.

    PS: Aber noch besser ist es, wenn du die Verwendung von globalen Variablen auf ein Minimum reduzierst. Damit handelst du dir nur Schwierigkeiten ein.



  • Neokil schrieb:

    Die Variablen extern zu deklarieren, reicht es da wenn ich extern vorne dran setzt?

    Ja.
    hpp:

    extern const int MeineVariable;
    

    cpp:

    const int MeineVariable = 123;
    

    ~EDIT: Zu langsam~



  • werden die #defines eigentlich mit includiert oder muss ich die in jeder Datei extra machen?



  • Neokil schrieb:

    werden die #defines eigentlich mit includiert oder muss ich die in jeder Datei extra machen?

    Das, dass du mit #define machst nennt man Makro. Und was für Makros meinst du?



  • ich habe in der Datei einige defines nach dem Prinzip "#define COLOR_FRIEND 0xFF4444FF"



  • Neokil schrieb:

    ich habe in der Datei einige defines nach dem Prinzip "#define COLOR_FRIEND 0xFF4444FF"

    *kotz* Was sagtest du noch gleich?



  • Benutze anstatt #define Konstanten, denn dafür sind sie da. 😉
    Also:

    const unsigned COLOR_FRIEND = 0xFF4444FF;
    


  • 314159265358979 schrieb:

    Benutze anstatt #define Konstanten

    Oder wenn es geht, namenlose Enumatoren (benötigen keinen Speicher im Gegensatz zu den Konstanten).



  • EOutOfResources schrieb:

    314159265358979 schrieb:

    Benutze anstatt #define Konstanten

    Oder wenn es geht, namenlose Enumatoren (benötigen keinen Speicher im Gegensatz zu den Konstanten).

    Die Konstanten werden von jedem halbwegs normalen Compiler doch sowieso wegoptimiert.



  • ok, ich werde es berücksichtigen...
    Vielen Dank für alles!



  • EOutOfResources schrieb:

    ...(benötigen keinen Speicher im Gegensatz zu den Konstanten).

    Sondern? Wo sollten die konstanten Werte herkommen? Magie?



  • Tachyon schrieb:

    EOutOfResources schrieb:

    ...(benötigen keinen Speicher im Gegensatz zu den Konstanten).

    Sondern? Wo sollten die konstanten Werte herkommen? Magie?

    Die werden direkt aus dem Internet runtergeladen und landen im sogenannten IRAM (Internet-RAM), so dass sie im normalen RAM keinen Platz beanspruchen. Logisch, oder? 🤡



  • Tachyon schrieb:

    EOutOfResources schrieb:

    ...(benötigen keinen Speicher im Gegensatz zu den Konstanten).

    Sondern? Wo sollten die konstanten Werte herkommen? Magie?

    Ich hoffe mal, dass du wirklich keine Ahnung hast. In dem Fall:

    // Fall 1:
    const int x = 42;
    f(x);
    

    Ohne Optimierung bezeichnet x im Prinzip eine Speicherstelle, an der der Wert 42 liegt. Beim Funktionsaufruf wird diese Speicherstelle adressiert, ausgelesen und der Wert an f übergeben.

    In Assembler etwa so:

    x    dd 42             ; Doubleword mit dem Wert 42
    ...
         push x
         call f
    

    Mit Optimierung ergibt sich dagegen das gleiche wie wenn man es gleich so geschrieben hätte:

    // Fall 2:
    f(42);
    

    In dem Fall liegt die 42 direkt im Code, sie wird nicht adressiert. In Assembler:

    push 42
          call f
    

    (Mein Assembler ist extrem eingerostet, ich hoffe man kann das einigermaßen entziffern, am Prinzip ändert das nichts.)

    Das ist damit gemeint, wenn man sagt, x benötgt Speicher oder eben nicht.



  • EOutOfResources schrieb:

    😞 C++-Code gehört in .cpp- und in .hpp-Dateien! Können wir das mal in die FAQ bringen?

    Nein, weils Geschmacks- und Konventionssache ist. Als Source-Erweiterungen sind neben .cpp auch .C, .cc und .cxx durchaus üblich. Für Header ist neben .hpp auch .hxx und .h üblich. Erlaubt ist sowieso alles, ich kenne Projekte, die (pseudo)-C++ benutzen und so gruselige Dinge wie .ko oder .kst für Konstanten, .def für typedefs und Makros (*würg*) und ähnliches benutzen.



  • Bashar schrieb:

    ...In dem Fall liegt die 42 direkt im Code, sie wird nicht adressiert...

    Und weils ein RValue ist belegt es keinen Speicher? Ich meinte schon, was ich sage. Wenn der Compiler das so wie Du hier zeigst optimieren würde, dann wäre das sogar ziemlich bescheinden, weil dann an jeder Stelle an der die Konstante benutzt wird ein neues Literal im Code stehen würde. Da braucht dann quase Speicher im Quadrat.



  • Tachyon schrieb:

    Bashar schrieb:

    ...In dem Fall liegt die 42 direkt im Code, sie wird nicht adressiert...

    Und weils ein RValue ist belegt es keinen Speicher?

    Doch, aber das ist mit der Aussage gemeint.

    Ich meinte schon, was ich sage. Wenn der Compiler das so wie Du hier zeigst optimieren würde, dann wäre das sogar ziemlich bescheinden, weil dann an jeder Stelle an der die Konstante benutzt wird ein neues Literal im Code stehen würde. Da braucht dann quase Speicher im Quadrat.

    Eine globale Konstante wie hier das COLOR_FRIEND zu adressieren kostet auch jedesmal einen vollen Pointer, also kommst du damit speichertechnich nicht besser weg. Dazu kommt der Performanceverlust durch den Speicherzugriff.



  • Bashar schrieb:

    Eine globale Konstante wie hier das COLOR_FRIEND zu adressieren kostet auch jedesmal einen vollen Pointer, also kommst du damit speichertechnich nicht besser weg. Dazu kommt der Performanceverlust durch den Speicherzugriff.

    Ja, das ist ganz bestimmt praxisrelevent, und ein Grund, Konstanten zu vermeiden. 🙄
    Btw. kommt in der Realität das Gleiche raus, egal wie man es macht.


Anmelden zum Antworten