Konstante in separater Datei
-
du meinst
#ifndef X #define X #endif?
Ja ist in der Header Datei drin.
Mit diesen Direktiven gehts trotzdem nicht.
-
Besser ist es, wenn du in die Guards den Namen deiner .h-Datei packst (siehe mein Beispiel) - dann müsste es auch funktionieren.
-
Edit: was ist denn die genaue Fehlermeldung?
-
Also nur zum verständnis: In der Header datei als
static const char* X = "Hallo";deklarieren?
Was hat das static da für eine Funktion, das versteh ich nicht so ganz. Gibt das static dem Compiler zu verstehen, dass diese Variable für alle Übersetzungseinheiten gleich ist?
Genaue Fehlermeldung:
error LNK2005: "char const * const X" (?X@@3PBDB) already defined in Haupt.obj
fatal error LNK1169: one or more multiply defined symbols foundEdit: Mit static funktionierts, aber warum das funktioniert ist mir nicht ganz klar.
-
Da diese Frage immer wieder falsch beantwortet wird: Linkerfehler haben in erster Linie nichts mit Include-Guards zu tun!
Das Problem ist, dass die Variable mehrfach definiert wird. In den Header gehört eine Deklaration:
extern const char* const X; // das 2. const macht den Zeiger erst konstantIn einer Implementierungsdatei muss die Definition stehen:
extern const char* const X = "hallo";Bei Konstanten könnte man auch interne Bindung nutzen (indem man keine Speicherklasse angibt), aber dann wird die Variable für jedes Modul einzeln erstellt. Das gleiche Verhalten erreicht man mit der Speicherklasse
static.Übrigens sollte man stets versuchen, globale Variablen zu vermeiden.
-
Warum funktioniert aber eine Konstantendefinition für einfache Datentypen wie const int auch mit Zuweisung?
-
Ok, danke Nexus, hätte aber noch 2 Fragen:
- Warum gibt er mir bei static keinen Fehler? Also wenn ich in der Header Datei
static const char* X = "Hallo";schreibe?
- Für was steht denn in
const char* const Xdas erste const?
-
ichben schrieb:
Warum funktioniert aber eine Konstantendefinition für einfache Datentypen wie const int auch mit Zuweisung?
Wie angetönt: Weil
const-qualifizierte globale Variablen standardmässig (d.h. ohne explizite Angabe einer Speicherklasse) intern gelinkt werden.
-
Variablen, die static sind, existieren nur in dieser Übersetzungseinheit und sind von anderen ÜE aus nicht erreichbar, dafür kannst du den gleichen Namen auch in anderen ÜE verwenden.
Das bedeutet zwar, dass die Variable in jeder ÜE einmal existiert, aber die meisten Linker führen z.B. gleiche Stringkonstanten zusammen, so dass sie nur einmal im Binary auftauchen.Don Quijote schrieb:
- Für was steht denn in
const char* const Xdas erste const?
Das erste const bezieht sich auf das char - d.h. es handelt sich um einen Zeiger auf ein konstantes char. Erst das zweite const macht auch den Zeiger selbst konstant.
-
Don Quijote schrieb:
- Warum gibt er mir bei static keinen Fehler? Also wenn ich in der Header Datei
static const char* X = "Hallo";schreibe?
Weil du durch das
staticexplizit eine nicht-konstante Variable mit interner Linkage versiehst. Der Linker erstellt eine unabhängige Variable pro Modul.Don Quijote schrieb:
- Für was steht denn in
const char* const Xdas erste const?
Das bezieht sich auf das
char, auf das der Zeiger verweist (und nicht etwa auf den Zeiger selbst). Wenn duXdereferenzierst, erhältst du Zugriff aufconst char, d.h. du kannst die Zeichen nicht verändern. Das ist bei Stringliteralen wie"Hallo"auch sinnvoll.
-
Na klar, macht Sinn,
Vielen Dank an alle Beteiligten.
btw.: Das hier hab ich noch nie in irgendeinem Tutorial gelesen.
-
Athar schrieb:
Variablen, die static sind, existieren nur in dieser Übersetzungseinheit und sind von anderen ÜE aus nicht erreichbar, dafür kannst du den gleichen Namen auch in anderen ÜE verwenden.
Ja.
staticin Headern ist aber eher ungewöhnlich. Das Problem ist eher relevant, wenn man in einer Implementierungsdatei ein globales Symbol erstellt, welches sich mit Bezeichnern in anderen Modulen überschneiden könnte. Dann empfehlen sich übrigens anonyme Namensräume.Athar schrieb:
Das bedeutet zwar, dass die Variable in jeder ÜE einmal existiert, aber die meisten Linker führen z.B. gleiche Stringkonstanten zusammen, so dass sie nur einmal im Binary auftauchen.
Du musst hier vorsichtig sein, dass du nicht zwei Dinge vermischst: Stringliterale, welche das Programm im statischen Speicherbereich hält, und globale Variablen (hier Zeiger, die auf Stringliterale verweisen). Die Speicherklasse von Variablen kann der Programmierer beeinflussen, die von Stringliteralen nicht.
Don Quijote schrieb:
btw.: Das hier hab ich noch nie in irgendeinem Tutorial gelesen.
Sinnvoller wäre es auch, du würdest ein Buch lesen. Du wirst noch einiges von C++ nicht mitkriegen, wenn du dein Wissen aus Internettutorials zusammensammelst. Oft empfohlen werden z.B. der C++ Primer oder Thinking in C++ (auch gratis als Online-PDF erhältlich).
-
Ok, hab mich vlt. falsch ausgedrückt, ich habe bereits ein Buch gelesen, allerdings eher für Anfänger. Trotzdem danke für den Tipp.
-
Nexus schrieb:
Du musst hier vorsichtig sein, dass du nicht zwei Dinge vermischst: Stringliterale, welche das Programm im statischen Speicherbereich hält, und globale Variablen (hier Zeiger, die auf Stringliterale verweisen). Die Speicherklasse von Variablen kann der Programmierer beeinflussen, die von Stringliteralen nicht.
Aber auch hier gilt, dass kein physischer Speicher für die Variablen bereitgestellt werden muss, sofern deren Adresse nicht angefordert wird.
Letztendlich wollte ich darauf hinaus, dass static nicht unbedingt die Binarygröße erhöhen muss.