Pointermathematik/-symbolik



  • Okay also leider habe ich von so etwas überhaupt keine Ahnung also hier die Probleme

    man hat:

    class CA;
    
    struct SB
    {
        static test(CA *cA, longint SB_in_CA);
        VariableA;
        (...)
    }
    
    class CA
    {
    public:
        (...)
        SB sB;
        (...)
    };
    

    Eine Klasse vom gleichen Typ ist ja immer gleich aufgebaut, demnach müßte es ja möglich sein die Position einer Variable innerhalb der Klasse zu bestimmen.
    Mit welchem Befehl bestimmt man jetzt:

    longint SB_in_CA=???;
    

    Okay und jetzt hat man

    static SB::test(CA *cA, longint SB_in_CA)
    {
        // Der Code der falsch ist und berichtigt werden soll
        (cA+SB_in_CA)->VariableA=1;
    }
    

    Also zu der Funktion test übergibt man den Pointer zu einer Klasse vom Typ CA. Dadurch das man die Variable "SB_in_CA" hat, die genau sagt wo in der Klasse CA sich die Struktur SB befindet, kennt man den Ort der gesuchten Struktur. Jetzt möchte ich dieses wie jede Strukt SB benutzen, so dass ich von da auf VariableA zugreifen kann. Aber ich habe keine Ahnung wie ich das schreiben soll 😞
    Danke im voraus.



  • wie wärs mit cA->sb.VariableA

    ?

    [ Dieser Beitrag wurde am 27.04.2003 um 21:28 Uhr von Bashar editiert. ]



  • cA->sB.VariableA; (groß 😎

    und static weg bei der implementierung und die anderen fehler verbessern



  • Oh sorry da hatte ich was falsch erklärt. Ich mein die struct SB kennt den Aufbau der Klasse CA nicht.

    Man hat nur die Struct SB mit der Funktion test wo eine unbekannte Klasse "CA" vorkommt. Aber man weiß wo in der Klasse "CA" sich die struct SB befindet, denn das wird durch die Variable SB_in_CA angegeben



  • Gibt s da irgendeinen Standart-Rückgabetyp?
    Wenn nicht, reicht static alleine vor ner Funktion nicht



  • wenn SB den Aufbau von CA nicht kennt, ihn aber kennen muß, dan solltest du ihr selbigen bekannt machen. So macht man das eben.



  • wenn SB den Aufbau von CA nicht kennt, ihn aber kennen muß, dan solltest du ihr selbigen bekannt machen. So macht man das eben.

    Das habe ich auch am Anfang gemacht (und es hat auch alles gut funktioniert), aber weil mir diese struct so gut gefiel, will ich die jetzt ganz "unabhängig" und separat haben.
    Um das hinzukriegen müssen aber die beiden oben genannten Probleme gelößt werden.
    -------
    Diese nochmal zusammengefasst:
    1)
    wie bestimmt man den Ort einer Variable relativ zu der Klasse in der er ist

    class CA
    {
    public:
        (...)
        SB sB;
        (...)
    };
    
    const longint SB_in_CA=???;
    

    Wenn man
    einen Pointer einer unbekannten Klasse (CA *cA)
    hat und man aber weiß,
    wieviele byte weiter sich eine vom Typ bekannte struct befindet(longint SB_in_CA);
    wie kann man dann auf diese struct zugreifen?

    ??? (cA+SB_in_CA)->VariableA=1; ???
    


  • wenn es eine instanz der klasse SB in CA gibt, dann weiß die instanz doch, wo sich die variable befindet. also so
    cA->sB.VariableA;

    😕



  • das ist lustig, irgendwie weiß ich nicht genau, was du wirklich willst vor allem mit deinem longint... soll das ein zeiger auf eine elementvariable darstellen?

    naja, viellleicht hilft dir das bsp trotzdem:

    class B;
    
    class A {
    public:
       void afoo (B *b); //ein Zeiger, weil A nichts über den aufbau von b weiß
    };
    
    class B {
    public:
       A a; //hier eine instanz, A ist schon vollständig da.
       void bbar ();
    };
    
    void B::bbar () { a.afoo(this); } //alles klar
    void A::afoo (B *b) { b->bbar(); } //auch alles klar, weil zu !diesem! zeitpunkt
    //A und B schon beide vollständig definiert sind
    
    void funktion (B *b) {
        b->a.afoo(b); //auch alles möglich. nach den klassendefinitiionen weiß
    //jede funktion alles über sie
    }
    
    typedef void (B::*memptr_t) (void); //zeiger auf eine member-funktion
    
    void foz (B *b, memptr_t ptr_to_memberfun) {
        (b->*ptr_to_memberfun) (); //funktion aufrufen, auf die ptr_to_memberfun zeigt
    }
    
    typedef A B::*aptr_t; //Zeiger auf ein A Element von B
    
    void baz (B *b, aptr_t ptr_to_membervar) {
        (b->*ptr_to_membervar).afoo(b); //zuerst das A holen, auf das 
          //ptr_to_membervar zeigt und dann afoo mit b als argument dafür aufrufen
    }
    
    //Zum Ausprobieren
    int main() {
    
        B *b = new B;
    
        b->bbar ();
        b->a.afoo (b);
    
        memptr_t bbar = &B::bbar;
        aptr_t a_von_b = &B::a;
    
        foz (b, bbar);
        baz (b, a_von_b);
    
          delete b;
    }
    

    so ich hoffe das war kompakt und verständlich genug...
    nicht ausprobieren, es kommt nicht viel weiter, als bis in
    b->bbar (); 😃 weil die funktion ja a.afoo aufruft, die ruft b->bbar auf etc.



  • Das tut mir jetzt wirklich extrem leid das ich wohl wirklich zu blöd bin euch das zu erklären 😞
    (@davie Das Bsp. hat mir leider nicht geholfen)

    Okay und vergeßt meine Beispiele da oben ich versuche es jetzt einfach mal nur anders.
    (Ich möchte den Moderator bitten die ganze sch**** darüber zu löschen, damit es nicht unübersichtlich wird)

    Man hat eine Klasse in der sich irgendwo eine Variable befindet.
    z.B.

    class CA
    {
    public:
        int a;
        int b;
        double c;
        int gesuchterOrt; // weiter oben hattte ich es mit struct SB bezeichnet
        int d;
    };
    

    So das heißt jetzt also:
    befindet sich beispielsweise cA Ca im 100. Byte im Arbeitsspeicher dann ist
    cA.a im 100. Byte
    cA.b im 102. Byte // Nur für den Fall das int 2 Byte groß ist, denn genau weiß ich das nicht 😉
    cA.c im 104. Byte
    cA.gesuchterOrt im 108. Byte
    cA.d im 110. Byte

    So und ich möchte jetzt die Differenz zwischen 108 und 100 = 8 haben.
    Da eine Klasse vom gleichen Typ immer gleich aufgebaut ist, werden das auch immer 8 Byte sein.
    Diese Zahl wollte ich dann in der Variable SB_in_CA speichern, und weil man die Anzahl der Bytes "abzählen" kann wollte ich diese Variable vom Typ int machen. Aber ich weiß nicht mit welchem Befehl man auf diese "8" kommen kann.

    const longint SB_in_CA=???;
    

    Das war jetzt Problem Nr 1
    Jetzt kommt Nr 2

    Jetzt hat man den Pointer einer beliebigen klasse. Ich bezeichne den Typ des Pointers mal mit void* damit man sieht das die Klasse wirklich beliebig ist. Also:

    void * eine_Klasse= Der_Ort_von_der_beliebigen_Klasse;
    

    So und in der Klasse von der man den Typ nicht kennt befindet sich jetzt irgendwo die Variable int x.
    Man weiß aber wie viele Bytes von *eine_Klasse weiter sich diese Variable int x befindet, denn das hatte man ja durch die Varbiable SB_in_CA ermittelt. Wie kann man jetzt auf diese Variable x zugreifen?
    Also wie "bewegt" man von void *eine_Klasse eine bestimmte Zahl von Bytes weiter und wandelt dies dann in einen int Pointer um.

    Baoh ich hoffe das ist jetzt klarer. Wenn nicht sagt bitte genau wo es unverständlich ist.

    [ Dieser Beitrag wurde am 29.04.2003 um 19:36 Uhr von Janko editiert. ]



  • du willst praktisch sowas:

    #include <iostream>
    using namespace std;
    
    class A {
    public:
        int a;
        int b;
        int c;
    };
    
    typedef int A::*ptr;
    
    int main () {
    
        ptr c = &A::c;
        void *v = (void*)c;
    
        A a;
        a.a = 1;
        a.b = 2
        a.c = 4;
        void *aptr = &a;
    
        int *vaptr = (int*)aptr;
        while ((char*)v) { ((char*)vaptr)++; --((char*)v); }
    
        cout << a.c << " = " << *vaptr << endl;
    }
    

    kannst ja mal ausprobieren, ob das bei dir geht.
    standardkonform ist das aber nicht mehr, da schon das casten von &A::c nach void* undefiniert ist (afair)
    schau dir dein problem lieber noch mal an und überleg dir eine andere lösung



  • wieso machs du es so umständlich?

    CA b;
    SB::test(b, ((char*)&b.sB) - ((char*)&b));
    

    vielleicht solltes du dich mal mit templates bescheftigen

    template<typename TofClass, typename TofMember>
    void test(TofClass & t, TofMember (TofClass::*p) )
    {
        (t.*p)->VariableA = 1;
    }
    
    int main()
    {
        CA b;
        test( b, &b::sB );
    }
    


  • offsetof



  • mir scheint, für die ganzen probleme, von nem kassenzeiger auf das member zu kommen, ist kein void* und kein offset nötig. das machen normale memberzeiger auch. irgendwie kann ich dem problem nicht folgen.
    wenn du es mit gewallt wilst, hilft bestimmt sowas wie
    int offset=(char*)&(((Klasse*)4711)->member)-(char*)(4711);
    aber das ist ganz schrecklich.

    ich muß gestehen, daß ich sowas schon gemacht habe. aber es ist schrecklich. die lösungen, die wie typedef int A::*ptr; anfangen sind viel geiler, weil sie das typsystem von c++ nicht vergewaltigen und außerdem auch klappen, wenn du nen anderen compiler nimmst.



  • Okay also das mit Klassenzeiger->member hat mich schon mal richtig weiter gebracht.
    ---
    Das andere Problem habt ihr auch gelöst. Jedoch nicht 100%ig so, wie ich es wollte.
    (Aber trotzdem bis hierhin danke!!!)
    Ihr habt den Ort einer Variable in der Klasse so bestimmt:

    CA b;
    int X= ((char*)&b.sB) - ((char*)&b);
    

    Und eigentlich war das Problem noch komplizierter 😉 denn zur Zeit des Funktionsaufrufs kennt man nur den Typ der Klasse, hat sie aber selbst noch nicht erstellt.

    Ich habe aber dafür eine mögliche Lösung gefunden
    (durch probieren und rumspielen nach einer Stunde)

    Ich erkläre das mal am Beispiel:

    Man hat

    class A {
    public:
        int b;
        int c;
        int d;
    };
    

    und man will den Ort von d in A haben.
    Das macht man so.

    int A::* H=&A::d;       // Bei dieser Klasse ist H dann 8 (in Bytes)
    

    Jetzt möchte ich das in eine int Variable kriegen aber ich weiß keinen guten Weg wie man es umwandeln soll. Eigentlich müsste es ja möglich sein, da man ja jeden Pointertyp in jeden anderen umwandeln kann, aber hier geht es nicht.
    Ich habe dann das Problem mit der Konvertierung einfach umgangen, indem ich einen Pointer J gemacht habe der auf H zeigt und den man dann ja, im Gegensatz zu H, in jeden Pointer anderen umwandeln kann. In I wurde dann der Wert von J gespeichert.

    int A::* H=&A::d;
    int *J=(int*)&H;
    int I=*J;           // I=8 (in Bytes)
    

    Okay die letzten beiden Zeilen konnte ich zusammenfassen

    int A::* H=&A::d;
    int I=*(int*)&H;
    

    Aber bei den beiden übrigen Zeilen weiß ich nicht wie ich das machen soll. Ich möchte es aber gerne zu einer Zeile zusammenfassen, da ich es nur als Parameter benutzen werde.

    Mir kommen insgesamt 3 Lösungsansätze in den Sinn wie man "A::*" in "int" in einer Zeile umwandeln könnte, die ich aber alle nicht hinkriege

    Es gibt einen direkten Umwandlungsbefehl, den ich nicht kenne
    2)
    Die beiden Zeilen kann man durch einfache befehle wie ,&,(int) irgendwie zusammenbringen
    3)
    Die extra Funktion

    template<typename V_Typ>
    V_Typ* make_Pointer(V_Typ v_Typ)
    {
        return &v_Typ;
    }
    

    machen, so dass man schreiben kann

    int I=*(int*)make_Pointer(&A::d);
    

    Wobei ich dann irgendwie folgende Warnung wegbekommen müsste:
    "Adresse einer lokalen Variablen oder eines temporaeren Wertes wird zurueckgegeben."

    Hey, oder gibt es so eine Funktion wie diese bereits als Standartbefehl?
    ---

    Falls jemand Lösungen zu einem der 3 Ansätze hat, bitte schreiben.
    Danke im voraus

    [ Dieser Beitrag wurde am 01.05.2003 um 15:01 Uhr von Janko editiert. ]



  • struct foo {
        int a;
        int b;
        int c;
    };
    
    int C = *(int*)&foo::c;
    

    deine template funktion macht folgendes:

    template <class T>
    T *bar (T t) {
      return &t;
    }
    
    //probier mal das ganze mit int:
    int *bar (int t) {
      return &t; //siehst du, was den compiler aufregt? i ist eine lokale kopie!
    }
    
    //und mit bar(&foo::c) passiert das:
    int foo::* * bar (int foo::*t) {
       return &t;
    }
    

    du gibst also einen zeiger auf eine lokale kopie von einem int foo::* zeiger zurück. geht auch nicht gut.
    bedenke: int foo::* ist bereits ein zeiger, und du willst ja keinen zeiger auf einen zeiger.

    im übrigen sind konvertierungen von zeigern auf elementvariablen zu irgendwelchen anderen typen außer zeiger auf elementvariablen der selben klasse nicht erlaubt:

    struct foo {
       int i; 
       double d;
       char c;
    };
    
    int main () {
        int foo::*ip = &foo::i;
        ip = reinterpret_cast<int foo::*> (&foo::d);  //ist erlaubt und genauso sinnvoll wie:
    
        int i, *ip2 = &i;
        double d;
        ip2 = reinterpret_cast<int*> (&d);
    
        int *i = reinterpret_cast<int*> (&foo::i); //ist NICHT erlaubt! und sollte 
        //bei einem standardkonformen Compiler nicht funktionieren (gcc3.2 zb)
        //ein Grund, um auf C casts zu verzichten, den damit lässt sich ALLES konvertieren:
        int *i = (int*)&foo::i;
    }
    

    also im prinzip passt du nicht mehr ganz in dieses forum



  • struct foo {
        int a;
        int b;
        int c;
    };
    
    int C = *(int*)&foo::c;
    

    Ich weiß jetzt nicht ganz warum du das hingeschrieben hast, bei mir funktioniert es nicht, bei dir etwa?
    Ich erhalte folgenden Fehler:
    error C2440: 'type cast' : 'int foo::*' kann nicht in 'int *' konvertiert werden
    Es gibt keinen Kontext, in dem diese Konvertierung moeglich ist
    **
    Inzwischen habe ich aber die Lösung selbst gefunden.

    int C=(int)&((foo*)0)->c;

    Das ist jetzt (endlich) die Stelle eines Members innerhalb der Klasse.
    🙂 🙂 🙂
    **
    -----

    int *i = reinterpret_cast<int*> (&foo::i); //ist NICHT erlaubt! und sollte 
        //bei einem standardkonformen Compiler nicht funktionieren (gcc3.2 zb)
        //ein Grund, um auf C casts zu verzichten, den damit lässt sich ALLES konvertieren:
        int *i = (int*)&foo::i;
    

    Ist klar das es nicht erlaubt ist, hat ja bei mir auch nicht funktioniert.
    Ich sehe aber bei deinen Kommentaren leider nicht ganz durch.
    Was meinst du genau mit "C" casts und bezieht sich dein "den" (was sicherlich denn heißen sollte) auf C casts oder auf die Zeile code darunter?
    Falls 2teres dann ist das schade, denn der Code funktioniert bei mir nicht. Ich erhalte wie oben folgenden Fehler:
    error C2440: 'type cast' : 'int foo::*' kann nicht in 'int *' konvertiert werden
    Es gibt keinen Kontext, in dem diese Konvertierung moeglich ist

    -----

    im übrigen sind konvertierungen von zeigern auf elementvariablen zu irgendwelchen anderen typen außer zeiger auf elementvariablen der selben klasse nicht erlaubt:
    [...]
    also im Prinzip passt du nicht mehr ganz in dieses forum

    Warum nicht? Oder hatte mein Code vom letzten Post etwa bei dir nicht funktioniert? (Hierrauf bitte antworten)

    class A {
    public:
        int b;
        int c;
        int d;
    };
    int A::* H=&A::d;
    int I=*(int*)&H;
    


  • 😃 zum glück hat meinen fehler noch niemand entdeckt:
    der C Cast ist hier sogar auch nicht erlaubt! fehler meinerseits (und von gcc 😮 )

    wie gesagt, deshalb kann ich auch (int)&foo::c ohne fehlermeldung den compiler schlucken lassen!



  • wie gesagt, deshalb kann ich auch (int)&foo::c ohne fehlermeldung den
    compiler schlucken lassen!

    Kannst du mir mal genau sagen wie du das gemacht hast? Bei mir funktioniert ja die Zeile nicht



  • ich gebe es einfach ein, keine warnung keine fehlermeldung.

    mein Compiler ist gcc 3.2 bzw. mingw


Anmelden zum Antworten