Multiple Definition - Hilfe!



  • Hallo zusammen,

    Leider brüte ich schon seit mehreren Tagen über einen Linker Fehler.

    Folgende Error-Meldung in dem Kompilierungsfenster:

    debug/cycmea.o:C:\work\Analyzer_rev2-build-desktop/../Analyzer_rev2/cycmea.cpp:150: multiple definition of `cycmea::pasBufOut'

    Diese gibt es einfach rund 100x mit verschiedenen Variablen (immer cycmea.cpp & main.cpp).

    Ansich sollte dies ja nicht passieren, da ich die Header mittels #ifndef #define #endif umklammere.

    Das ganze passiert aber nur wenn ich im main.cpp die cycmea.h Datei inkludiere.
    Belasse ich das Main vorerst leer, erscheint nichts.

    Ich habe folgendes bereits überprüft:
    - Projekt auf doppelnamige Variabeln überprüft
    - Header die mehrmals inkludiert worden sind, rausgenommen & nur noch einmal inkludiert
    - #ifndef #define #endif
    - Kopf gegen Tisch 🙄

    Was kann ich noch probieren?

    Die Main Funktion sieht im übrigen so aus; falls das helfen sollte:

    #include "cycmea.h"
    #include <QtCore/QCoreApplication>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        cycmea::Start();
        return a.exec();
    }
    

    Der cycmea.h 'include' Teil:

    #ifndef CYCMEA_H
    #define CYCMEA_H
    
    #include "GENconv.h"
    
    #include <iostream>
    #include <math.h>
    
    #include <QObject>
    
    #include "cyctcpip.h"
    

    Gruess 🙂



  • Schon versucht den Inhalt der int main() funktion auszukommentieren (return 0 oder sowas nicht vergessen), und den include QtCore/QtCoreApplication zu entfernen? tritt der Fehler dann immer noch auf?
    Komplettes clean/rebuild versucht?

    Eventuell bräuchte man auch die komplette cycmea.h, bzw eine minimale version, bei der der compilerfehler immer noch auftrifft wäre ideal.



  • C++Beginner2 schrieb:

    Ansich sollte dies ja nicht passieren, da ich die Header mittels #ifndef #define #endif umklammere.

    Gegen "multiple definition" hilft das nicht! So etwas geht nicht in einem Header, der mehrfach inkludiert wird:

    int a;
    void f() {}
    

    Such mal hier im Forum, die Frage wird so ungefähr alle 2 Tage gestellt 😉



  • Hast du im Header evtl. Funktionen defniert und nicht nur deklariert?
    Die Fehlermeldung ist nicht vollstädnig. Der Code den du gepostet hast auch nicht.
    Bei der Fehlermeldung müsste noch stehen "first defined here: ..." oder was ähnliches, auf jeden Fall eine Angabe, wo die Funktion/Variable auch noch definiert worden ist. Wenn du nicht grade die Funktionsklammern abgeknipst hast, ist cycmea::pasBufOut wohl eine statische Variable, die du an mehreren Stellen definierst. Zeig uns doch mal bitte den Code, der in cycmea.cpp um Zeile 150 rum steht. Dann such mal in deinen Headern und *.cpps nach "pasBufOut" und schau wo du es sonst noch verwendest.

    Sinnvollste Möglichkeit, den Fehler zu finden: Code reduzieren. Das geht so (Pseudocode):

    loop
    {
      identifiziere Codeabschnitt, der vermutlich nichts mit dem Fehler zu tun hat
      kommentiere ihn aus
      compiliere neu
      switch {
        case neuer/anderer Fehler: 
          schlecht auskommentiert
          also wieder einkommentieren
          und anders auskommentieren
        case Fehler bleibt wie gehabt:
          next loop
        case Fehler verschwunden:
          Fehlerursache auskommentiert.
          auskommentierten Code analysieren und Fehler beheben. 
          fertig
      }
    }
    

    Mit Codefetzen kann man hier nicht viel anfangen, vor allem dann nicht, wenn sie den Fehler nicht enthalten. Da du nicht weißt, wo der Fehler ist, musst du wohl den kompletten Code posten, aber bitte nachdem du ihn wie beschrieben auf ~50 zeilen reduziert hast.



  • C++Beginner2 schrieb:

    Ansich sollte dies ja nicht passieren, da ich die Header mittels #ifndef #define #endif umklammere.

    Suche nach Erklärungen zu
    - Getrennter Übersetzung / separate compilation
    - ÜE (Übersetzungseinheit) / TU (translation unit)
    - ODR (one definition rule)

    Du verletzt hier die ODR. Include-Guards helfen Dir, Mehrfachdefinitionen nur innerhalb einer Übersetzungeinheit auszuschließen -- nicht über mehrere Übersetzungseinheiten hinweg!

    Um die ODR zu verstehen, musst Du erstmal verstehen, was ÜEs sind und wie Preprocessor, Compiler und Linker zusammenspielen.



  • Hallo,

    Also die komplette cycmea.h Datei sieht folgendermassen aus (aufgrund der Grösse -> pastebin.com); http://pastebin.com/fSdS0L9z

    Implementationen von Funktionen sind keine vorhanden.

    @pumuckel.
    Der Fehler wird zwar angeblich in der cycmea.cpp angezeigt, jedoch ist dort nichts derartiges zu finden da die Variabeln alle in der Header-Datei deklariert werden. 🙂

    Gruess



  • C++Beginner2 schrieb:

    Der Fehler wird zwar angeblich in der cycmea.cpp angezeigt, jedoch ist dort nichts derartiges zu finden da die Variabeln alle in der Header-Datei deklariert werden. 🙂

    Dem Compiler ist das schei*egal, in welcher Datei irgendwas definiert wird. Der Preprocessor holt sich den Kram aus diversen Dateien, interpretiert die Macros und das, was dabei rauskommt ist die ÜE, die dem Compiler sozusagen übergeben wird, so dass er daraus eine Objektdatei zaubern kann.

    Folgendes zu Deinem Header:

    const string blah = "soundso"; impliziert dynamische Initialisierung. Du darfst stattdessen auch schreiben const char blah[] = "soundso"; Für String-Konstanten ist das eigentlich vorzuziehen, weil dann nicht unnötig Freispeicher reserviert und Zeichenketten kopiert werden müssen, bevor die main loslegt

    Zeile 68 ist eine ODR-Verletzung, solltest Du diesen Header in mehrere ÜEs einbinden und die dann linken. Das trifft auch auf 78-84 zu, sowie 103-109, u.s.w.

    Schau auch in deinem C++ Buch nach unter den Stichwörtern "Bindung" (Linkage) und "const". Dann wirst Du auch verstehen, warum

    const int dings = 23; // voellig OK im Header
    int bums = 22;        // NICHT OK im Header
    

    Top-level Constness impliziert nämlich interne Bindung. Größere Arrays solltest Du eigentlich nicht in Headern definieren -- also auch nicht mit interner Bindung. Die tauchen dann nämlich doppelt und dreifach in der EXE auf. Arrays kann man im Header unvollständig deklarieren und in einer cpp-Datei definieren:

    // header
    extern const char message42[];
    extern const int sometable[16];
    
    // cpp
    #include "header"
    const char message42[] = "duppdidu";
    const int sometable[16] = {3,2,1,0};
    

    Wozu das extern gut ist, kannst Du Dir dann, nachdem Du Bindung und Const recherchiert hast, vielleicht sogar schon denken. Im Header ist es jedenfalls notwendig. In der Cpp kann man es weglassen, wenn es vorher schon mit extern deklariert wurde (zb durch das Einbinden des Headers).



  • Wenn du das Buch schon in der hand hast, schau dir mal Klassen an. Du hast da tonnenweise freie Funktionen und zig typedefs und structs, das sieht auf den ersten Blick aus, als wolltest du eigentlich Klassen mit Methoden haben.
    Dazu hast du ebenso tonnenweise globale Variablen, und sowas ist wirklich ekelhaft. Da kann man schon fast froh sein dass der Compiler das nicht compilieren will 😉


Anmelden zum Antworten