Linkerfehler



  • MFK schrieb:

    bwbg schrieb:

    Nach einem Schnellblick gehe ich schwer davon aus, dass überall s.g. Include-Guards fehlen. Diese verhindern das Mehrfachinkludieren von Header-Dateien:

    Nein, Probleme mit den Include-Guards verursachen Compilerfehler, keine Linkerfehler. Es ist schon so, wie CStoll es beschrieben hat.

    ... es ist ja auch kein Problem mit Include-Guards, sondern ohne ... 🤡

    Ansonsten gehe ich mit CStoll d'accord.

    Grüße...

    Heiko



  • Hallo, vielen Dank für die schnellen Antworten!!

    Ich programmier leider noch nicht soviel CPP, ich denke aber, das ein Include Guard dabei ist, so hab ich das zumindest verstanden. Ich verwende Visual C++ Professional.

    Ich hab versucht den Tipp mit extern umzusetzen, da die Funktionen alle auf die gleiche Variable zugereifen sollen, die Header sehen jetzt so aus:

    struct wichtig
    {
    	int Zahl;
    }Zahlen;
    
    class Header1
    {
    	void Funktion();
    	void Funktion3()
    	{
    		int Zahl = Zahlen.Zahl;
    	}
    };
    

    und

    extern wichtig Zahlen;
    
    class Header2
    {
    	void Funktion();
    	void Funktion3()
    	{
    		int Zahl = Zahlen.Zahl;
    	}
    };
    

    Die cpp dateien so:

    #include "StdAfx.h"
    
    wichtig Zahlen;
    
    void Header1::Funktion()
    {
    	int jj;
    
    	jj = Zahlen.Zahl;
    }
    

    und

    #include "StdAfx.h"
    
    wichtig Zahlen;
    
    void Header2::Funktion()
    {
    	int JJ = 3;
    	JJ = Zahlen.Zahl;
    
    }
    

    Jetzt meckert aber der Compiler:
    C:\Dokumente und Einstellungen\Andy\Desktop\dfghsdgh\Header1.cpp(4) : error C2086: 'Zahlen' : redefinition

    Tut mir leid, aber was habe ich falsch gemacht, vielen Dank nochmal

    Viele Grüße
    Andreas



  • Andreas_L schrieb:

    ...ich denke aber, das ein Include Guard dabei ist...

    =>

    Andreas_L schrieb:

    ...
    Jetzt meckert aber der Compiler:
    C:\Dokumente und Einstellungen\Andy\Desktop\dfghsdgh\Header1.cpp(4) : error C2086: 'Zahlen' : redefinition
    ...

    Offensichtlich nicht. 😃

    "include guard" ist kein Feature eines C++-Compilers, sondern eine Programmiertechnik (sprich: "Etwas, das Du in Deinem Source machen musst"), die genau solche "Redefinitions" verhindert.

    In Deinem Fall würde ich Folgendes machen:

    • globale Variablen vermeiden (Hier: "Zahlen")
    • ... erst Recht in Headern,
    • "precompiled Headers" abschalten (in Deiner "Visual Studio"-Entwicklungsumgebung) und
    • Jeden Header mit folgendem Block einfassen:
    #ifndef HEADERNAME_INCLUDE_GUARD
    #define HEADERNAME_INCLUDE_GUARD
    
    // .... Hier kommt dann Dein Source
    
    #endif // HEADERNAME_INCLUDE_GUARD
    

    Letzteres ist Dein "Include Guard" ("HEADERNAME" sollte natürlich für den Namen des jeweiligen Headerfiles stehen und nicht überalle gleich heißen).

    Gruß,

    Simon2.



  • Danke,
    jetzt siehts so aus:

    #ifdef HEADER1_INCLUDE_GUARD 
    #define HEADER1_INCLUDE_GUARD 
    struct wichtig
    {
    	int Zahl;
    }Zahlen;
    
    class Header1
    {
    	void Funktion();
    	void Funktion3()
    	{
    		int Zahl = Zahlen.Zahl;
    	}
    };
    
    #endif // HEADER1_INCLUDE_GUARD
    

    und

    #ifdef HEADER2_INCLUDE_GUARD 
    #define HEADER2_INCLUDE_GUARD 
    
    extern wichtig Zahlen;
    
    class Header2
    {
    	void Funktion();
    	void Funktion3()
    	{
    		int Zahl = Zahlen.Zahl;
    	}
    };
    #endif
    
    // stdafx.h : include file for standard system include files,
    //  or project specific include files that are used frequently, but
    //      are changed infrequently
    //
    #ifdef StdAfx_INCLUDE_GUARD 
    #define StdAfx_INCLUDE_GUARD 
    
    #if !defined(AFX_STDAFX_H__0B335010_3D3D_4528_892F_2AE1F3666FF2__INCLUDED_)
    #define AFX_STDAFX_H__0B335010_3D3D_4528_892F_2AE1F3666FF2__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    #define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
    
    #include <stdio.h>
    #include "Header1.h"
    #include "Header2.h"
    
    #endif
    
    // TODO: reference additional headers your program requires here
    
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
    
    #endif // !defined(AFX_STDAFX_H__0B335010_3D3D_4528_892F_2AE1F3666FF2__INCLUDED_)
    

    An den Cpp-Dateien hat sich ja nichts verändert.

    Jetzt meckert er in den Cpp datein immer:
    C:\Dokumente und Einstellungen\Andy\Desktop\dfghsdgh\Header1.cpp(4) : error C2146: syntax error : missing ';' before identifier 'Zahlen'

    #include "StdAfx.h"
    
    wichtig Zahlen;
    
    void Header1::Funktion()
    {
    	int jj;
    
    	jj = Zahlen.Zahl;
    }
    

    Du meintest, dass man möglichst keine Globalen Variablen machen sollte.
    Aber was soll man machen, wenn eine Struktur von mehreren Klassen verwendet wird?
    Mit der obigen Änderung hab ich dann aber doch ein Include-Guard, oder nciht?
    Gab es nicht auch soetwas mit #pragma once?

    Was muss man denn jetzt noch machen, damit er das endlich komplett übersetzt?

    Viele Grüße
    Andreas



  • Die extern-Deklaration gehört ja auch in den Header:

    struct wichtig
    {
      int Zahl;
    }
    
    extern wichtig Zahlen;
    
    class Header1
    {
      ...
    };
    

    (noch besser ist es natürlich, wenn du auf die externe Variable komplett verzichtest)



  • Danke, aber irgendwie klappt jetzt gar nichts mehr:

    In die Headerdateien sollte der Includeguard. zudem sollte dort die Variable mit extern definiert werden:

    #ifdef HEADER1_INCLUDE_GUARD 
    #define HEADER1_INCLUDE_GUARD 
    
    struct wichtig
    {
    	int Zahl;
    };
    extern wichtig Zahlen;
    
    class Header1
    {
    	void Funktion();
    	void Funktion3()
    	{
    		int Zahl = Zahlen.Zahl;
    	}
    };
    
    #endif // HEADER1_INCLUDE_GUARD
    

    und

    #ifdef HEADER2_INCLUDE_GUARD 
    #define HEADER2_INCLUDE_GUARD 
    
    extern wichtig Zahlen;
    
    class Header2
    {
    	void Funktion();
    	void Funktion3()
    	{
    		int Zahl = Zahlen.Zahl;
    	}
    };
    #endif
    

    In die CPP Dateien sollte ich doch wichtig Zahlen reinschreiben:

    #include "StdAfx.h"
    
    wichtig Zahlen;
    
    void Header1::Funktion()
    {
    	int jj;
    
    	jj = Zahlen.Zahl;
    }
    

    und

    #include "StdAfx.h"
    
    wichtig Zahlen;
    
    void Header2::Funktion()
    {
    	int JJ = 3;
    	JJ = Zahlen.Zahl;
    
    }
    

    Bei stdafx.h hab ich das einfach so belassen, wie es bei Mircrosoft vorgegeben wurde:

    // stdafx.h : include file for standard system include files,
    //  or project specific include files that are used frequently, but
    //      are changed infrequently
    //
    
    #if !defined(AFX_STDAFX_H__0B335010_3D3D_4528_892F_2AE1F3666FF2__INCLUDED_)
    #define AFX_STDAFX_H__0B335010_3D3D_4528_892F_2AE1F3666FF2__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    #define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
    
    #include <stdio.h>
    #include "Header1.h"
    #include "Header2.h"
    
    // TODO: reference additional headers your program requires here
    
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
    
    #endif // !defined(AFX_STDAFX_H__0B335010_3D3D_4528_892F_2AE1F3666FF2__INCLUDED_)
    

    Die Probleme bleiben aber immer noch:
    C:\Dokumente und Einstellungen\Andy\Desktop\dfghsdgh\Header1.cpp(4) : error C2146: syntax error : missing ';' before identifier 'Zahlen'

    Wenn ich dann Zahlen auskommentiere kommt:

    C:\Dokumente und Einstellungen\Andy\Desktop\dfghsdgh\Header1.cpp(6) : error C2653: 'Header1' : is not a class or namespace name

    Das deutet doch dann darauf hin, dass Header1.h überhaupt nicht mehr eingebunden wurde oder nicht?

    Ich hatte in der ersten Headerdatei nicht extern davor geschrieben, weil ich extern so verstanden habe, dass der nur darauf verweist, dass die Variable woanders definiert wird. In Header1 wird sie aber definiert, deshalb dachte ich muss man extern da weglassen.

    Viele Grüße

    Andreas



  • Erstens: Du sollst in EINER CPP-Datei die Variable definieren.

    Zweitens: In Header2 ist der Typ "wichtig" nicht bekannt, da macht die Definition Probleme.

    PS: Wofür soll die Variable 'Zahlen' eigentlich gut sein?



  • HI, die Variable Zahlen sollte einfach nur als Beispiel dienen.

    In meinem realen Projekt habe ich nämlich eine Struktur, in der VerkaufsPreise definiert werden.
    Zu Beginn werden diese Preise aus einer INI-Datei ausgelesen und in der Struktur gespeichert.
    Nun sollen die verchiedenen Klassen darauf zugreifen können, deshalb sollte eine globale Variable vorhanden sein, auf die jede Klasse einfach zugreifen kann.
    Ich hab jetzt die Variablen als Member gemacht, damit gehts, hätte micht nur mal interessiert, warum sich der Linker immer beklagt.

    Eine letzte Frage noch:
    Bisher hab ich keinen IncludeGuard verwendet und es gab keine Compilerfehler.
    Muss ich das trotzdem noch ändern, weil so wie ich den IncludeGuard eben hatte ging es ja nicht.

    Viele Grüße
    Andreas



  • Der Linker beschwert sich, weil die selbe Variable in mehreren Übersetzungseinheiten definiert wurde - und er jetzt nicht weiß, welches die "richtige" ist.

    Ich würde übrigens die wichtig-Klasse mit allem in eine eigene Datei auslagern, anstatt sie an eine der Header-Klassen anzuhängen (in der nächsten Entwicklungsstufe sogar als Singleton angelegt:

    //wichtig.h
    struct wichtig
    {
      int Zahl;
    };
    
    extern wichtig Zahlen;
    
    //wichtig.cpp
    #include "wichtig.h"
    wichtig Zahlen
    
    //HeaderX.h
    #include "wichtig.h"
    class HeaderX
    {
      ...
    };
    
    //HeaderX.cpp
    #include "HeaderX.h"
    ...
    
    //main.cpp
    #include "Header1.h"
    #include "Header2.h"
    
    int main()
    {...}
    


  • Danke, werd mal gucken wie ich das so umsetzen kann 🙂



  • Was vielleicht auch nicht ganz unwichtig ist:

    #ifndef (if not defined)

    statt

    #ifdef (ifdef)

    oder aber die Variante von (D)evil, welche ich persönlich noch nicht ausprobiert habe.

    Grüße...

    Heiko



  • bwbg schrieb:

    Was vielleicht auch nicht ganz unwichtig ist:

    #ifndef (if not defined)
    ...

    😮 😮 😮 😡 😮 😮 😮
    Oh ja !! Sorry !!!

    Mein Fehler,

    Simon2.


Anmelden zum Antworten