String-Konstanten



  • Hallo

    ich habe ein Header-file mit Stringkonstanten.

    Das sieht ungefähr so aus:

    namespace defines
    {
       // die Namen für die Services
       static const char *STRING1          = "ABCD";
       static const char *STRING2          = "EFGH";
       static const char *STRING3          = "IJKL";
    }
    

    liefert mir aber als Warnung im Compileprozess "...defined but not used", falls ich eine Konstante nicht verwende.

    Da ich aber mit den Warnungen nicht leben will und sie auch nicht ausschalten will, brauche ich für Stringkonstanten in Headerfiles eine bessere Lösung!

    Eine Alternative wäre die Realisierung über Makros ( #define ), aber dafür kann ich mein Herz auch nicht erwärmen.

    Wie handhabt ihr das? Mit STL-Strings?



  • It0101 schrieb:

    Da ich aber mit den Warnungen nicht leben will und sie auch nicht ausschalten will, brauche ich für Stringkonstanten in Headerfiles eine bessere Lösung!

    Aber wieso willst du Konstanten definieren, die du nie nutzt 😕

    It0101 schrieb:

    Eine Alternative wäre die Realisierung über Makros ( #define ), aber dafür kann ich mein Herz auch nicht erwärmen.

    Mag ich auch nicht.

    It0101 schrieb:

    Wie handhabt ihr das? Mit STL-Strings?

    Ich nutze für Zeichenketten eigentlich immer std::string. Immerhin ist char[] implizit nach std::string konvertierbar, umgekehrt nicht.



  • out schrieb:

    Aber wieso willst du Konstanten definieren, die du nie nutzt

    Weil ich eine allgemein und vielseitig nutzbare "Bibliothek" habe, die verschiedenste Funktionen anbietet, von denen man nicht immer alle auch braucht.



  • namespace defines
    {
       // keine Konstante:
       static const char* STRING1          = "ABCD";
      // Konstante:
       static const char STRING2[]         = "EFGH";
      // auch Konstante:
       static const char* const STRING3    = "IJKL";
    }
    


  • Danke, das war des Rätsels Lösung 😉

    Ich habe mich dann für die Version mit "[]" entschieden.



  • out schrieb:

    Ich nutze für Zeichenketten eigentlich immer std::string.

    Wieso? std::string hat einen Anwendungsfall: Dynamische Strings*. Das ist hier nicht der Fall.

    *Kopieren, Vergrößern, usw.



  • Sone schrieb:

    out schrieb:

    Ich nutze für Zeichenketten eigentlich immer std::string.

    Wieso? std::string hat einen Anwendungsfall: Dynamische Strings*. Das ist hier nicht der Fall.

    *Kopieren, Vergrößern, usw.

    Der Overhead ist mir relativ egal. :p



  • Also bitte...

    constexpr char foo[] = "foo";
    


  • It0101 schrieb:

    Ich habe mich dann für die Version mit "[]" entschieden.

    Zähl mal, wie oft eine von den Zeichenketten im Binary landet. Die steht ggf n-mal da drin, wenn du den Header jeweils in n Übersetzungsheinheiten einbidest, in denen du die Konstante nutzt.

    Ich sehe nicht, was gegen Separation zwischen .h und .cpp spricht:

    // dies steht im Header
    namespace foo {
      extern const char str1[];
      extern const char str2[];
      extern const char str3[];
    }
    
    // dies steht in der cpp-Datei
    namespace foo {
      extern const char str1[] = "dings";
      extern const char str2[] = "bums";
      extern const char str3[] = "blafasel";
    }
    

    Und so kann man sich auch sicher sein, dass diese Srings nicht mehrfach im Executable stehen.



  • Wieso sind die strings in der .cpp datei extern? (Das ist eine ernstgemeinte Frage!)



  • extern sagt an, dass die Definition in einer anderen Datei stattfindet. Ohne extern würde der Linker denken, dass die Konstanten mehrfach definierte Symbole sind und entsprechende Fehlermeldungen ausgeben.



  • Hyde++ schrieb:

    Wieso sind die strings in der .cpp datei extern? (Das ist eine ernstgemeinte Frage!)

    Möglicherweise verstehst du die Sache mit der "Bindung" nicht ganz. extern erfüllt primär die Funktion, einer Sache "externe Bindung" zu geben. Externe Bindung ist aber "normalerweise" voreingestellt. Deswegen macht es auch keinen Unterschied, ob du bei

    int i = 23;
    

    extern davor schreibst, oder nicht. i hat sowieso externe Bindung.

    extern erfüllt aber noch eine andere Funktion. Es kann aus einer Definition eine Deklaration machen. Nehme ich den Initialisierer von oben weg:

    int i;
    

    dann ist das hier immer noch eine Definition. Aus dieser Definition wird aber mit extern

    extern int i;
    

    eine Deklaration. Merken: extern + kein Initialisierer = Deklaration. Das wird auch im Header ausgenutzt. Da will man die Dinger nur deklarieren, nicht definieren.

    Und jetzt kommt der letzte Baustein: Die voreingestellte Bindung bei top-level const Variablen ist intern. Das heißt,

    const int i = 23;
    

    definiert i mit interner Bindung (Das ist eine C++ Regel, die es in C nicht gibt). Wenn ich das nicht möchte, muss ich schreiben

    extern const int i = 23;
    

    und das hier ist jetzt eine Definition von i mit externer Bindung. Es ist aber immer noch eine Definition, weil wir hier einen Initialisierer auf der rechten Seite stehen haben. extern + kein Initialisierer gilt also nicht.

    Eine Interne Bindung bekommt man auch ohne top-level const : Mit static :

    static int i;
    

    Das ist eine Definition einer Variablen i mit interner Bindung. Jede Übersetzungseinheit kann so etwas enthalten und jede von diesen Übersetzungseinheiten hat dann ihr eigenes i. Wenn du nur ein "globales" i haben willst, auf das man per Name von überall aus zugreifen kannst, dann willst du keine interne sondern eine externe Bindung haben.

    Btw: wenn Du in der cpp-Datei den Header inkludierst (wie es sich eigentlich gehört) dann werden im Header ja schon die Variablen mit externer Bindung deklariert. Dann kann man sich in der cpp-Datei auch das extern sparen. Aber falsch ist es dort nicht.

    Kompliziert, ich weiß, aber so ist C++ nun einmal gewachsen. Einige Schlüsselwörter können unterschiedliche Dinge in unterschiedlichen Kontexten. extern , static und const gehören dazu. extern beeinflusst die Bindung und macht ggf aus einer Definition eine Deklaration.
    static beeinflusst die Bindung (gegenteil von extern in der Hinsicht) oder die Lebenszeit der definierten Variablen. const verbietet einen Schreibzugriff und kann aber auch die Bindung beeinflussen.

    Aber es macht immer noch einigermaßen Sinn. 🙂 Beispielsweise ist das mit der internen Bindung bei Konstanten praktisch. So kannst du einfach

    const double pi = 3.14159265;
    

    in einem Header schreiben und den überall einbinden, ohne dass sich der Linker über mehrere Definitionen desselben pi s beschwert, weil ja wegen der internen Bindung alle ihre eigene pi-Variable haben. Allerdings würde ich das nur ungern mit Arrays tun wollen. Die gäbe es dann doppelt und dreifach in der ausführbaren Datei -- je nachdem, wie viele Übersetzungseinheiten den Header einfügen.



  • Vielen Dank für die ausführliche Erklärung!


Anmelden zum Antworten