Frage zu extern



  • Hallo,

    um globale Variablen zu vermeiden, bin ich auf das Schlüsselwort 'extern' gestoßen. Nur komme ich damit nicht zurecht.

    .h

    #ifndef EXTERN_H_INCLUDED
    #define EXTERN_H_INCLUDED
    
    extern char ch;
    extern const int X;
    
    #endif // EXTERN_H_INCLUDED
    

    .cpp

    #include "extern.h"
    
    char ch = 'a';
    extern const int X = 5;
    

    main

    #include "extern.h"
    #include <iostream>
    #include <array>
    
    int main()
    {
    
        std::cout << "X: " << X << '\n';
        std::cout << "ch: " << ch << '\n';
        std::array <int, X> ch_ = {4,3,2,1,0}; //hier Fehler
    }
    

    Ohne die array-Deklaration läuft es durch, mit bekomme ich folgende Fehler:

    |10|error: the value of 'X' is not usable in a constant expression|
    |5|note: 'X' was not initialized with a constant expression|
    |10|note: in template argument for type 'long long unsigned int' |
    |10|error: scalar object 'ch_' requires one element in initializer|
    

    Wie muss ich das richtig machen, bzw ist das alles sinnig?



  • std::array <int, X> ch_ = {4,3,2,1,0}; //hier Fehler
    

    Mir ist nicht bekannt, dass ein Template-Argument - was zur Compilezeit benötigt wird - durch eine Variable ersetzen lässt.

    Das sollte gehen:

    #define X 5
    std::array <int, X> ch_ = {4,3,2,1,0};
    


  • oder besser

    constexpr int X = 5;
    

  • Mod

    Wie muss ich das richtig machen, bzw ist das alles sinnig?

    Nein, es ist nicht sinnig. Der Compiler muss den Typ einer Variable eindeutig für jede Übersetzungseinheit bestimmen können; X ist aber nur in der anderen initialisiert.

    Definiere X stattdessen im Header, ohne extern . So hat es internal linkage und kann in mehreren Übersetzungseinheiten verwendet werden.



  • @ Arcoth

    aber dann ist es doch wieder eine globale Variable? Bzw wie ich es immer gemacht habe? Oder bezieht sich das nur auf die Konstante?


  • Mod

    extern ist dazu da, Variablen global zu machen. Du hast da irgendetwas gänzlich missverstanden.



  • Das kann gut sein. Bin mir auch sehr unsicher.

    Bisher habe ich im Header zB const int X =5; geschrieben, dachte aber dies ist verkehrt.



  • lemon03 schrieb:

    Das kann gut sein. Bin mir auch sehr unsicher.

    Bisher habe ich im Header zB const int X =5; geschrieben, dachte aber dies ist verkehrt.

    Nö, da ist jetzt nix verkehrt dran. Das kannst du so z.B. in einen Header packen. Das top-level const auf Ebene der Namensräume ändert die "Bindung" von X von extern zu intern. Das heißt im Wesentlichen, dass jede cpp-Datei, wo das direkt oder indirekt (über #include) auftaucht, ihre eigene X-Variable hat. Das Gegenteil dazu ist externe Bindung. Dann gibt es genau ein solches X, was sich alle teilen. Externe Bindung ist eigentlich der Standard sonst.

    Konstanten mit externer Bindung, dessen Wert nicht über eine Header-Datei verraten wird, kann aber kein "konstanter Ausdruck" sein. Ein "konstanter Ausdruck" nennen wir das, was zur Übersetzungszeit vom Compiler berechenbar ist. Und der schaut nicht in andere cpp-Dateien rein, sondern nur in die, die man gerade übersetzt (und all die Header, die da noch #includiert werden).

    Edit: Dass const die Bindung verändert ist ein C++ Feature, was Dir im Gegensatz zu C die per Präprocessor-Macro definierten Konstanten ersparen soll. Vielleicht hast Du einen C-Artikel gelesen, der erklärt, dass man da extern verwenden muss, um keine Mehrfachdefinitionen zu haben.

    HTH,
    kk



  • Ok danke. Unter der Bedingung, das ich jetzt nicht alles sofort in Gänze verstanden habe, eine Frage noch;

    Sollte ich nicht-Konstanten dann weiterhin ein extern wie oben voransetzen? Denn sonst verstehe ich nicht, warum auch bei Nachfrage von mir von globalen Variablen abgeraten wurde, denn sie sind doch nicht anderes dann?

    EDIT: Aber eigentlich benutze ich nur Konstanten als globale Variablen, weshlab sich das erledigt haben müsste?



  • krümelkacker schrieb:

    Edit: Dass const die Bindung verändert ist ein C++ Feature, was Dir im Gegensatz zu C die per Präprocessor-Macro definierten Konstanten ersparen soll. Vielleicht hast Du einen C-Artikel gelesen, der erklärt, dass man da extern verwenden muss, um keine Mehrfachdefinitionen zu haben.

    HTH,
    kk

    Jepp, gelesen habe ich tatsächlich was dazu. Habe ein eBook vom 'Der C++ Programmierer' ergattert, dort geht es bei 'Programmstrukturierung' und 'One Definition Rule' um diese Sachen. Aber wie schon geschrieben kann es gut sein, das ich etwas missverstanden habe.



  • lemon03 schrieb:

    Ok danke. Unter der Bedingung, das ich jetzt nicht alles sofort in Gänze verstanden habe, eine Frage noch;

    Sollte ich nicht-Konstanten dann weiterhin ein extern wie oben voransetzen? Denn sonst verstehe ich nicht, warum auch bei Nachfrage von mir von globalen Variablen abgeraten wurde, denn sie sind doch nicht anderes dann?

    EDIT: Aber eigentlich benutze ich nur Konstanten als globale Variablen, weshlab sich das erledigt haben müsste?

    Ggf versteh' ich die Frage nicht ganz. Wenn Du "globale und änderbare Variablen" haben willst, brauchst du "extern" bei der Deklaration im Header, ja. Aber von sowas würde ich eher abraten, soweit das geht, da ein globaler Zustand zu Überraschungen und Probleme führen kann, siehe zum Beispiel den strtok-Fuckup.



  • Die Problematik verstehe ich schon, weshalb ich auch immer Konstanten verwende. Sind ja nur wenige, die sich auch gar nicht ändern könnten, selbst wenn man es drauf anlegen würde.


Anmelden zum Antworten