[definition statische klassen member] windoof(cl) <-> schlimlux (gcc3.4)



  • Hi @all
    Wiedermal das altbekannte problem mit der instanzierung statischer member Variablen.

    ------------- h --------------
    class A {
    public: 
    const static int groesse = 10; 
    int nr[groesse]; 
    };
    -------------cpp --------------
    leer
    

    laut standard kann man integer bereist in der deklaration definieren.
    leider hat der gcc kompiler noch immer keine ahnung davon
    --> unter windows keine fehlermeldung und linux kommt dann die meldung beim linken, dass er nicht auf "groesse" referenzieren koenne.

    also änderung in:

    ------------- h --------------
    class A {
    public: 
    const static int groesse;// = 10; 
    int nr[groesse]; 
    };
    -------------cpp --------------
    const int A::groesse = 10;
    

    --> beim compilieren: int nr[groesse] -> error: data member may not have variably modified. buw. windows: error C2057: Konstanter Ausdruck erwartet

    klar. er sollte die groesse schon beim parsen des headers kennen.

    wie mach ich dies also dem gcc begreiflich?



  • Machs doch über nen enum.

    enum bla
    {
    blub = 10
    };
    
    int nr[blub];
    


  • Du koenntest einen aktuellen gcc z.B. aus der 4er Serie nehmen...
    Mit dem funktioniert das erste einwandfrei.



  • werde es mit dem enum machen...
    das mit gcc4.0 würd eich machen, aber da haben die von uns verwendeten mpi-implementierungen so ihre probleme mit 😉

    danke!



  • Du kannst doch die Konstante bei der Deklaration initialisieren und bei der Definition dann nicht. Dann hast Du eine optimierbare Konstante und einen Speicherplatz für das Objekt gleichzeitig 😮 😉

    ------------- h --------------
    class A {
    public:
    const static int groesse = 10;
    int nr[groesse];
    };
    -------------cpp --------------
    const int A::groesse;
    

    Schlucken sowohl gcc 3.3 als auch 4.1



  • muffmolch schrieb:

    ...
    laut standard kann man integer bereist in der deklaration definieren.

    ...meldung beim linken, dass er nicht auf "groesse" referenzieren koenne....

    Im Standard steht aber (IIRC) auch, dass so ein "static const ohne Definition" NICHT "adressierbar" ist. Im Gegensatz zu einem "normalen static const" ...

    Ich weiß zwar nicht, ob Du das irgendwo gemacht hast, wollte aber noch kurz darauf hinweisen. Ich weiß jetzt nicht, warum "die von Euch verwendeten mpi-Implementierungen ihre Probleme damit haben", aber es könnte vllt. genau das sein (die kann man nämlich auch nicht adressieren).

    Bei mir (gcc 4.3) funktioniert ebenfalls Dein Obiger Code tadellos.

    Dies hier zeigt das Problem

    class A {
    public:
    const static int groesse = 10;
    const static int groesse2;
    int nr[groesse];
    };
    
    const int A::groesse2 = 20;
    
    void f(int const& g) {
       cout << g << "\n";
    }
    
    int main() {
       A myA;
       myA.nr[0] = 3;
       f(myA.groesse); // => liefert Linkerfehlermeldung "undefined reference to `A::groesse'"
       f(A::groesse); // ebenfalls
       f(myA.groesse2); // => funktioniert tadellos
       f(A::groesse2); // ebenfalls
    
    ...
    

    Gruß,

    Simon2.



  • okay, das mit dem adressierbar war mir entfallen.
    macht aber sinn. "groesse" fungiert quasi als typsicheres "define" und wird nie initialisiert. "groesse2" hingegen schon, aber leider erst, wenn die arrays deklariert worden sind, was dann nicht den gewünschten effekt bringt...



  • muffmolch schrieb:

    ..."groesse" fungiert quasi als typsicheres "define" und wird nie initialisiert. "groesse2" hingegen schon, aber leider erst, wenn die arrays deklariert worden sind, was dann nicht den gewünschten effekt bringt...

    Ähhh, das habe ich jetzt nicht verstanden. Beide "groesse(n)" werden initialisiert.
    Und auch groesse2 kannst Du (wie von LordJaxxom beschrieben) zur Compilezeit initialisieren und als Arraygroße verwenden.
    Du darfst nur nicht auf die Definition verzichten ....

    Oder hab' ich da was mißverstanden ?

    Gruß,

    Simon2.



  • LordJaxom schrieb:

    Du kannst doch die Konstante bei der Deklaration initialisieren und bei der Definition dann nicht. Dann hast Du eine optimierbare Konstante und einen Speicherplatz für das Objekt gleichzeitig 😮 😉

    ------------- h --------------
    class A {
    public:
    const static int groesse = 10;
    int nr[groesse];
    };
    -------------cpp --------------
    const int A::groesse;
    

    Schlucken sowohl gcc 3.3 als auch 4.1

    irgendwie habe ich diese antwort übersehen 😉
    das hatte ich auch schon im sinn gehabt. ist denn garantiert, dass dann zur laufzeit grosse==10 ist oder ist das compilerabhängig?



  • LordJaxom schrieb:

    Du kannst doch die Konstante bei der Deklaration initialisieren und bei der Definition dann nicht. Dann hast Du eine optimierbare Konstante und einen Speicherplatz für das Objekt gleichzeitig 😮 😉

    ------------- h --------------
    class A {
    public:
    const static int groesse = 10;
    int nr[groesse];
    };
    -------------cpp --------------
    const int A::groesse;
    

    Schlucken sowohl gcc 3.3 als auch 4.1

    aber nicht windows 😞

    "public: static int const A::groesse " ist bereits definiert!



  • muffmolch schrieb:

    ...
    aber nicht windows 😞

    "public: static int const A::groesse " ist bereits definiert!

    "Windows" ist kein Compiler 😉

    Welchen verwendest Du denn ? evtl. VC6.0 ? Der ist ziemlich bekannt für seine "Standard-Unkonformität" (und Bugs)....

    Gruß,

    Simon2.



  • Würde mich auch interessieren, denn der 8er schluckts:

    // a.cpp
    #include <iostream>
    using namespace std;
    
    class A {
    public:
    	static const int groesse = 10;
    	int ary[groesse];
    
    	void y() { cout << sizeof(ary)/sizeof(ary[0]) << endl; }
    };
    
    const int A::groesse;
    
    void y(int const& p);
    void y(int const* p);
    
    int main(int argc, char* argv[])
    {
    	A a;
    	a.y();
    	y(A::groesse);
    	y(&A::groesse);
    }
    
    // b.cpp
    #include <iostream>
    using namespace std;
    
    void y(int const& p) { cout << p << endl; }
    void y(int const* p) { cout << *p << endl; }
    

    Ausgabe: Drei mal 10.



  • sorry, hatte in der tat nirgends erwähnt, dann ich den VC8-compiler verwende. schande über mein haupt.
    genauer gesagt verwende ich den vc8 kompiler mit sp1. bei diesem wurde viel verschlimmbessert... also tatsächlich teils harte bugs implementiert (kann z.B. qt4.x nicht mehr ohne patch installieren).

    jedenfalls funktioniert das letzte beispiel von LordJaxom so wie er es aufgeührt hat. er definiert ja auch beide in der cpp! zumindest scheint der compiler sowas zu schlucken.

    aber es geht nicht wenn man aus

    // a.cpp
    

    eine header datei

    // a.h
    

    macht
    -->(vc8.0) main.obj : error LNK2005: "public: static int const A::groesse" (?groesse@A@@2HB) ist bereits in afile.obj definiert.
    Release\dummy.exe : fatal [man]error LNK1169: Mindestens ein mehrfach definiertes Symbol gefunden.[/man]



  • Man sollte auch nichts in einer Header-Datei definieren (einzige Ausnahme sind Templates und Inline-Funktionen). Da der Header in verschiedenen Übersetzungseinheiten eingebunden wird, hast du in jeder dieser Übersetzungseinheiten ein Exemplar deiner static-Variable - und das sind idR zu viele für den Linker.

    (Und ehe du hier mit "aber ich habe doh Include-Guards verwendet" kommst - die verhindern nur, daß der Header doppelt in eine Übersetzungseinheit eingebunden wird, gegen Linker-Probleme kannst du auf Präprozessor-Ebene nichts mehr machen)



  • @CStoll:
    In diesem Thread geht es doch gerade um die Möglichkeit, statische Memberkonstanten bereits in der Klasse mit Werten zu belegen!? 😕

    Oder ist das in ISO 14882:2003 wieder gestrichen worden? 😉



  • CStoll schrieb:

    (Und ehe du hier mit "aber ich habe doh Include-Guards verwendet" kommst - die verhindern nur, daß der Header doppelt in eine Übersetzungseinheit eingebunden wird, gegen Linker-Probleme kannst du auf Präprozessor-Ebene nichts mehr machen)

    😃 keine sorge. damit wäre ich schon nicht gekommen. aber man deklariert normalerweise auch keine klassen in der implementierungsdatei, oder?

    jedenfalls dreht man sich bei diesem problem einfach im kreis. zumal die compiler die sache eben anders interpretieren. möchte man also den code auf mehreren plattformen zum laufen bringen, so muss man eben mit kleinen "krücken" wie dem enum arbeiten... (um die noch viel schlimmeren #ifdefs zu vermeiden)

    LordJaxom schrieb:

    @CStoll:
    In diesem Thread geht es doch gerade um die Möglichkeit, statische Memberkonstanten bereits in der Klasse mit Werten zu belegen!? 😕

    Oder ist das in ISO 14882:2003 wieder gestrichen worden? 😉

    genau darum geht es...



  • LordJaxom schrieb:

    @CStoll:
    In diesem Thread geht es doch gerade um die Möglichkeit, statische Memberkonstanten bereits in der Klasse mit Werten zu belegen!? 😕

    Ja, mit Werten belegen kannst du sie auch bereits in der Deklaration - aber das const int a::groesse; hat trotzdem nichts im Header zu suchen.



  • okay, dann nochmal ausführlich (wollte mir doch nur ein paar zeilen sparen...)
    folgendes funktioniert mit dem vc8 compiler und scheinbar auch mit gcc3.5 und 4.x:

    // main.cpp
    #include <iostream>
    using namespace std;
    
    class A {
    public:
        static const int groesse = 10;
        int ary[groesse];
    
        void y() { cout << sizeof(ary)/sizeof(ary[0]) << endl; }
    };
    
    const int A::groesse;
    
    void y(int const& p) { cout << p << endl; }
    void y(int const* p) { cout << *p << endl; } 
    
    int main(int argc, char* argv[])
    {
        A a;
        a.y();
        y(A::groesse);
        y(&A::groesse);
    }
    

    folgendes jedoch zumindest mit vc8.0 sp1 nicht

    // a.h 
    #include <iostream> 
    using namespace std; 
    
    class A { 
    public: 
        static const int groesse = 10; 
        int ary[groesse]; 
    
        void y() { cout << sizeof(ary)/sizeof(ary[0]) << endl; } 
    }; 
    
    // a.cpp <-man sehe und staune ;-)
    const int A::groesse; 
    
    //main.cpp
    void y(int const& p) { cout << p << endl; }
    void y(int const* p) { cout << *p << endl; } 
    
    int main(int argc, char* argv[])
    {
        A a;
        a.y();
        y(A::groesse);
        y(&A::groesse);
    }
    

    und so hatte ich es auch gemeint... mit genau diesem code bekommt man mit vc8 eben linker fehler! denn er scheint den standard so auszulegen, dass mit "groesse=10" im header zugleich die definition von A::groesse erfolgte.
    dadurch kommt er beim linken mit a.obj natürlich in bedrängnis.



  • Ah ok. Aus der kompletten a.cpp darf man natürlich keine a.h machen. Ich ging davon aus dass muffmolch da selbsttätig selektiert hat 😉

    Muss ich später nochmal ausprobieren, momentan installiere ich meinen Arbeitsplatz gerade neu 😡



  • LordJaxom schrieb:

    Muss ich später nochmal ausprobieren, momentan installiere ich meinen Arbeitsplatz gerade neu 😡

    *lol* das problem kenn eich nur allzu gut. gestern erst habe ich meinen arbeitsspeicher auf 4Gb augerüstet, damit vista mit 8 instanzen von VS zurecht kommt. scheinbar ist d aber noch was anderes im argen. aber auf ne neuinstallation habe ich derzeit so gar keine lust *end-off topic*


Anmelden zum Antworten