Define nicht global
-
Also ich ahbe ein Problem mit meinem/ meinen Projekten. Undzwar bekomme ich regelmäßig den LNK 2005 Fehler und scheine angeblich einige Header mehrfach zu includen.
Die bekannte Lösung sind ja nun include guards. Diese verwende ich aber in JEDER meiner Header im Sinne von:#ifndef XXX #define XXX //CODE #endif
Das sollte ja eigentlich laufen oder? Tun es aber nicht!!!
Also habe ich mal getestet, ob die mit define definierten Makros überhaupt in den anderen Headern zur Verfügung stehen. Und leider ist dem nicht so.
Wenn ich in einem meiner Header #define IRGENDWAS schreibe, dann steht dieser Wert in keinem anderen Header zur Verfügung.
Wie kann denn das sein?!
Das erklärt ja nun warum die Include Guard nicht laufen (der Wert ist halt nie definiert), aber wie dieses Phänomen auftritt verstehe ich eifnach nichtVielen Dank!
-
Dann machst du was falsch. Gib mal ein ganz einfaches Beispiel dafür, wie du es konkret machst und das bei dir nicht funktioniert.
-
Die include guards funktionieren, wenn der Header ein zweites Mal eingebunden wird. Das ist was ganz anderes als ein Makro, dass im Header 2 definiert wird und im Header 1 dann logischerweise noch nicht bekannt ist (denn der Präprozessor war ja noch gar nicht im Header 2).
Der LNK2005 besagt ja, dass irgendwas doppelt implementiert (nicht deklariert) wurde. Hast du in deinem Headern vielleicht etwas mehr als nur Deklarationen stehen? Bastele mal ein Minimal-Beispiel zusammen, das den Fehler aufweist und poste es hier.
-
Kleine Ergänzung. Ich habe mir die Fehler nochmal genauer angesehen.
Undzwar scheinen alle Units einzeln kompiliert zu werden!Daher ich habe 3 units A,B,C,D
in A definiere ich #define PFAD "Pfad zu C"
jetzt include ich A in B, und B in D.
Außerdem wird in der Unit B #include PFAD aufgerufen (daher das makro aus A)Nun passiert folgendes:
Ich erhalte einmal den Fheler, dass PFAD unbekannt ist und 2x den Fehler, dass die Datei nicht gefunden wurde (sie exisitert zugegebendermaßen auch nicht^^).
Das führt mich jetzt zu der Annahme, dass jede meiner Dateien einmal einzeln kompiliert wird.
Daher A wird kompiliert = kein Problem
Dann wird B kompiliert = Fehler, da A nicht mitkompiliert wird, daher PFAD unbekannt
und dann aus C und D die Meldungen, dass der Pfad nicht gefunden wurde, da dort natürlich alles verfügbar ist.
Wie bekomme ich denn hin, dass er die Dateien wirklucgh nur zusammen copy and pastet und dann nur das finale ergebniss kompiliert?!
Ich benutze vc++ 2008 express
-
Question12345 schrieb:
Das führt mich jetzt zu der Annahme, dass jede meiner Dateien einmal einzeln kompiliert wird.
Das ist auch so. Jede c/cpp-Datei ist eine Übersetzungseinheit und wird einzeln kompiliert. Die daraus entstandenen Objektdateien werden erst vom Linker zu einer gemeinsamen, breiigen Masse zusammengestampft. Und wenn der dann eine Funktion in 2 Objektdateien findet, meckert er.
Wenn du dein #define PFAD "Pfad zu C" in allen ÜEs verfügbar haben willst, dann definiere es in einem gemeinsamen Header (z.B. Shared.h) und inkludiere den in allen ÜEs.
-
Wie kann dann aber mein LNK 2005 entstehen. Ich habe in keiner cpp was doppelt. Nur operatoren im Header. Könnte es daran liegen?
-
Question12345 schrieb:
Daher ich habe 3 units A,B,C,D
Gut, zählen kannst du schon mal.
Question12345 schrieb:
jetzt include ich A in B, und B in D.
Damit meinst du jetzt aber keine cpp-Dateien, oder? Die darfst du niemals nicht per include irgendwo einbinden (doppelte Verneinung hier nur zur Verdeutlichung, minus mal minus gleich plus greift hier nicht
)! Das gibt dann quasi unausweichlich doppelte Definitionen.
-
Question12345 schrieb:
Daher ich habe 3 units A,B,C,D
in A definiere ich #define PFAD "Pfad zu C"
jetzt include ich A in B, und B in D.
Außerdem wird in der Unit B #include PFAD aufgerufen (daher das makro aus A)Entweder verstehe ich dich falsch oder du setzt define und include völlig falsch ein. In ersterem Fall musst du mal ein konkretes Beispiel für dein Problem geben, in letzterem Fall ist es die Ursache für dein Problem.
-
Question12345 schrieb:
Wie kann dann aber mein LNK 2005 entstehen. Ich habe in keiner cpp was doppelt. Nur operatoren im Header. Könnte es daran liegen?
Du bist mit dem Konzepten "Übersetzungseinheit" und "Getrennte Übersetzung" nicht vertraut. Include Guards verhindern nur das mehrfache Einbinden von Code innerhalb einer einzigen Übersetzungseinheit. Wenn die Header-Datei eine Definition einer Funktion(1) enthält, und dieser Header in mehr als eine ÜE eingebunden wird, dann wird sich der Linker beschweren. Übersetzten geht, "linken" nicht.
Ich schätze Dein Fall sieht in etwa so aus:
// header.hpp #ifndef HEADER #define HEADER void foo(int x) {} // Definition #endif // tu1.cpp #include "header.hpp" // tu2.cpp #include "header.hpp"
Dass Du die Definition nur einmal in einer Headerdatei stehen hast und die mit Includeguards geschützt hast, bringt Dir nichts, wenn Du den Header in mehreren CPP-Dateien einbindest. Die werden (logisch gesehen) unabhängig voneinander kompiliert. Dem Compiler ist das ziemlich egal, woher der ganze Code kommt. Der Preprocessor "setzt die ÜE zusammen" (fürgt Text aus anderen Dateien ein, macht die Makro-Ersetzung, etc). Wenn Du tu1.cpp und tu2.cpp kompilierst, bekommst Du zwei Objektdateien, die jeweils eine Definition von foo beinhalten. Da foo jeweils "external linkage" hat bezieht sich der Name auf diesselbe Funktion. Der Linker sieht zwei Definition, wobei nur eine erlaubt ist. ("Eine-Definition-Regel").
Lösung 1:
Definiere solche Funktionen in einer eigenen CPP-Datei und schreibe nur die Deklarationen in eine Header-Datei. (Sollte man meistens so machen)// foo.hpp #ifndef FOO #define FOO void foo(int x); // Deklaration #endif // foo.cpp #include "foo.hpp" void foo(int x) {} // Definition // tu1.cpp #include "header.hpp" // tu2.cpp #include "header.hpp"
Lösung 2:
Definiere Deine Funktion als "inline". Damit der Compiler Funktionen "inlinen" kann, muss er die Definition kennen. Dementsprechend darf die Definition in mehreren ÜEs auftauchen, vorrausgesetzt, dass es exakt die gleiche Def ist. Der Linker schmeißt Duplikate dann einfach raus.// header.hpp #ifndef HEADER #define HEADER void foo(int x) {} // Definition #endif // tu1.cpp #include "header.hpp" // tu2.cpp #include "header.hpp"
(Für Klassendefinitionen, Funktionstemplate-Definitionen und Definitionen statischer Elemente von Klassentemplates gilt diese Ausnahme auch).
Getrennte Übersetzung: Man will einzelne .c/.cpp Dateien separat übersetzen können, ohne in andere .c/.cpp Dateien gucken zu müssen. Um Funktionen aus anderen Übersetzungseinheiten aufrufen zu können, muss der Compiler zumindest eine Deklaration der Funktion gesehen haben.
Gruß,
SP(1: Funktion mit externer Bindung, welche keine Inline-Funktion und kein Funktionstemplate ist)