Adresse eines Pointers ermitteln



  • Hallo,

    wie kann ich die Adresse eines Pointers ermitteln, also der Ort, wo der Pointer im Speicher liegt (nicht die ZielAdresse). Und wie kann ich diesen Adress-Wert in einem Int speichern?

    Und gibt es weiterhin eine Möglichkeit herauszufinden, ob der Speicherbereich zum Stack, AllocHeap, oder Process Data gehört (will sagen; ob er lokal, alloziiert oder "program data" ist)?

    gruss,
    Barnski.



  • Hi,

    also die Adresse des pointers bekommst du mit hilfe des Adress operators. Aber ich kann mir nicht vorstellen das man mit standardmitteln bestimmen kann wo sich der speicher befindet.

    int * ptr = 0;
    int ** ptr_ptr = &ptr; // Zeiger auf Zeiger auf i
    


  • Ja also wenn ich den & (adress operator) verwende, muss ich dann auf (int)casten. Und dann kommt eine Warnung "truncating *[...] to int" (in MS VC++ 2003)..

    void* ptr;
    int a = 0;
    ptr = &a;
    a = (int) &ptr;   // hier warnt er mich...
    

    Is das der einzige Weg oder geht das auch ohne Warnung?

    gruss,
    Barnski.



  • Barnski schrieb:

    void* ptr;
    

    ptr ist eine Variable, wie jede andere auch. Wo die landet, bestimmst Du.
    Warum dort eine Warnung kommt, weiß ich nicht. Evtl. brauchst du reinterpret- oder static_cast.



  • Hast Recht, ich stelle einfach 3 Funktionen zur Verfügung, eine die eine adresse aufm stack nimmt, die andere von nem alloziierten Bereich und die dritte vom program data... (ich will mit der adresse des pointers etwas unterschiedliches machen, je nachdem wo er ist...)

    Der Fehler kam weil ich einen 64bit pointer auf einen 32bit int gecastet habe, deswegen die "warning, truncating..." meldung.

    folgender Code funktioniert ohne warnung:

    void* ptr;
    long long int a = 0;
    ptr = &a;
    a = (long long int) &ptr;   // keine truncating warnung mehr...
    

    allerdings wundert mich dass ich auf meiner 32bit maschine mit winxp 32bit einen 64bit pointer habe.. ?!

    An dieser Stelle würde mich vllt noch interessieren, wie ich mit den define und anderen präprocessor befehlen code für 32bit, 64bit oder andere systeme compilieren kann.

    gruss,
    Barnski.



  • Wieso willst du die Adresse überhaupt in einen int reinpacken? Pointer-Datentypen kann man doch genausogut direkt verrechnen und zwischen seinen Funktionen übergeben.

    (ich will mit der adresse des pointers etwas unterschiedliches machen, je nachdem wo er ist...)

    Ich überlege gerade, was man da für unterschiedliche Sachen anstellen können muß.



  • Barnski schrieb:

    Hast Recht, ich stelle einfach 3 Funktionen zur Verfügung, eine die eine adresse aufm stack nimmt, die andere von nem alloziierten Bereich und die dritte vom program data... (ich will mit der adresse des pointers etwas unterschiedliches machen, je nachdem wo er ist...)

    Der Fehler kam weil ich einen 64bit pointer auf einen 32bit int gecastet habe, deswegen die "warning, truncating..." meldung.

    folgender Code funktioniert ohne warnung:

    void* ptr;
    long long int a = 0;
    ptr = &a;
    a = (long long int) &ptr;   // keine truncating warnung mehr...
    

    allerdings wundert mich dass ich auf meiner 32bit maschine mit winxp 32bit einen 64bit pointer habe.. ?!

    An dieser Stelle würde mich vllt noch interessieren, wie ich mit den define und anderen präprocessor befehlen code für 32bit, 64bit oder andere systeme compilieren kann.

    gruss,
    Barnski.

    Wenn du VC++ verwendest kann es sein das der im 64-Bit Kompatibilitätsmodus kompiliert und mit 64Bit Zeigern arbeitet.
    => Siehe einstellungen

    BR evilissimo



  • CStoll schrieb:

    Wieso willst du die Adresse überhaupt in einen int reinpacken? Pointer-Datentypen kann man doch genausogut direkt verrechnen und zwischen seinen Funktionen übergeben.

    Meine Linked list die ich gemacht habe, hat für jedes Element einen Key vom Typ int, anhand dessen die elemente sortiert werden können (man kann ja auf elemente keinen < operator definieren, weil das item nich unbedingt ne Klasse sein muss...). Ich möchte die Pointer also nach ihrer Adresse im Memory sortieren, bzw danach suchen.

    CStoll schrieb:

    Zitat:
    (ich will mit der adresse des pointers etwas unterschiedliches machen, je nachdem wo er ist...)
    Ich überlege gerade, was man da für unterschiedliche Sachen anstellen können muß.

    Das brauche ich für meinen eigenen Garbage Collector. je nach dem, ob der pointer in einem alloziiertem Speicher definiert wurde, muss er weggeräumt werden, wenn der Speicher freigegeben wurde... deswegen muss ich bei einem free nach der adresse des memorys in meiner datenstruktur, vorerst linked list, suchen und dann alle pointers die darin hängen durchgehen... und dann jeweils im Ziel memory struct den refcount um 1 verringern. wenn keine pointer mehr darauf zeigen: freigeben.. so habe ich mir das vorgestellt. Mal sehen obs klappt, dann muss ich nie mehr selber aufräumen und muss keine Angst vor Memory leaks mehr haben 😋

    evilissimo schrieb:

    Wenn du VC++ verwendest kann es sein das der im 64-Bit Kompatibilitätsmodus kompiliert und mit 64Bit Zeigern arbeitet.

    Schön und gut, aber wie finde ich zur Laufzeit heraus, ob mein program auf einer 32bit oder 64bit machine oder sonst was läuft?
    je nach dem muss man dann doch anderen code ausführen...

    oder kann ich nichts mehr machen zur Laufzeit wenn ich mein program mit nur 32bit pointern kompiliert habe und das system jetz 64bit register hat? 😕



  • Barnski schrieb:

    Und gibt es weiterhin eine Möglichkeit herauszufinden, ob der Speicherbereich zum Stack, AllocHeap, oder Process Data gehört

    Theoretisch würde das schon gehen, nur ist das systemabhängig. Du müsstest zB wissen, von wo bis wo der Stack oder Freispeicher geht, und dann prüfen, ob die Adresse in diesem Bereich liegt.

    Barnski schrieb:

    folgender Code funktioniert ohne warnung:

    void* ptr;
    long long int a = 0;
    ptr = &a;
    a = (long long int) &ptr;   // keine truncating warnung mehr...
    

    Mag sein, allerdings ist dies kein gültiger C++ Code, da C++ kein long long kennt. Wenn du einen integralen Typ brauchst, der mindestens die Grösse eines Zeigers hast, dann solltest du eher auf size_t oder ptrdiff_t zurückgreifen. Evtl. noch portabler geht es mit einer Möglichkeit, die hier letztens diskutiert wurde. Dann schreibst du einfach

    typedef select_integer<bit_sizeof(void*), false>::result ptr_int;
    

    und castest dann immer nach ptr_int. Und was das Casten betrifft, da kann ich dich eigentlich nur an meine Signatur verweisen.

    Barnski schrieb:

    allerdings wundert mich dass ich auf meiner 32bit maschine mit winxp 32bit einen 64bit pointer habe.. ?!

    Du hast keinen 64 Bit Zeiger. Die Warnungen kommen, weil, wenn du für ein 64 Bit System kompilieren würdest, dann Probleme entstehen können.

    Barnski schrieb:

    Das brauche ich für meinen eigenen Garbage Collector.

    Ich hab irgendwie das Gefühl, das scheint in letzter Zeit in Mode zu kommen. Bedenke, C++ wurde nicht für GC konzipiert und C++ braucht auch keinen GC. GC hat einige entscheidende Nachteile, speziell zur Laufzeit. Beim scope-basierten Speicherhandling, wenn überhaupt, dann nur zur Entwicklungszeit. Aber selbst das kann man mit einigen Restriktionen minimieren.

    Barnski schrieb:

    Mal sehen obs klappt, dann muss ich nie mehr selber aufräumen und muss keine Angst vor Memory leaks mehr haben

    Ich räume auch nie selber auf und habe weder Angst vor, noch überhaupt Memory Leaks. Denk mal darüber nach. 😉 Stichwort: Container und Smart-Pointer

    Barnski schrieb:

    Schön und gut, aber wie finde ich zur Laufzeit heraus, ob mein program auf einer 32bit oder 64bit machine oder sonst was läuft?

    Musst du nicht. Für 32 und 64 Bit hast du sowieso unterschiedliche Kompilate. Die würden nativ sowieso nicht auf der jeweils anderen Plattform laufen. Und damit du portabel bleibst, keine festen Werte verwenden. Also nicht davon ausgehen, dass ein Zeiger 32 Bit breit ist, sondern sizeof(void*) * CHAR_BIT.



  • groovemaster schrieb:

    Theoretisch würde das schon gehen, nur ist das systemabhängig. Du müsstest zB wissen, von wo bis wo der Stack oder Freispeicher geht, und dann prüfen, ob die Adresse in diesem Bereich liegt.

    Ja genau, aber es wäre noch praktisch wenn das System dafür Funktionen bereitstellen würde.. und für den mem_heap start gibts ja noch das Problem, dass man nicht weiss, wie gross der program data Teil ist... Ganz zu schweigen wenn man dynamisch dll's reinladet. dann verschiebt sich doch auch was, der untere stack-ende vllt. Naja, ich lass es lieber ganz. Der Caller weiss ja idR wo eine Variable angelegt ist.

    typedef select_integer<bit_sizeof(void*), false>::result ptr_int;
    

    Danke für den Code. Habe ihn kopiert und eingesetzt, scheint zu funktionieren.

    Was den Garbage Collector angeht; Ich habe OOP mit Eiffel gelernt, eine Object-only Programmiersprache, in der ein GC bereits integriert ist. Mit C++ habe ich erst gerade angefangen objekt orientiert zu programmieren, und da fehlt mir einfach ein GC...
    Ich glaube dass es extrem kompliziert wird in einem AVL-Baum mit einer Doubly Linked List und vllt noch daranhängenden segmentbäumen oder sonst noch was, dann noch zu wissen welche Elemente/Knoten löschbar sind, ohne dabei die anderen Strukturen, die ineinander vernetzt sind, zu kompromitieren.

    Da ich bereits eine doubly linked list implementiert habe, und noch einen AVL-baum machen werde, denke ich ist es fast einfacher einen GC zu schreiben, als sich um die korrekte Aufräumarbeit zu kümmern, die wahrscheinlich sowieso nicht korrekt sein kann, und wenn doch, sie der Arbeit des GC ähneln muss, was wiederrum dafür spricht, direkt einen zu schreiben 😉

    Is ja nich so, dass man den für jede Kleinigkeit verwenden muss, sondern halt dort, wo es komplexe Vernetzung im Memory gibt.

    Ich denke es ist machbar, einen simplen und "naiven" GC zu schreiben, und wenn weitere Probleme auftauchen, werde ich mich wieder hier im Forum melden 🙂

    gruss,
    Barnski.



  • Meiner Meinung nach verfolgst du die falsche Strategie. Für C++ musst du deine Denkweise ändern. Ein Container (in deinem Fall der Baum) ist nur für seine eigene Speicherverwaltung verantwortlich, für die Speicherverwaltung der Elemente aber nicht. Sofern by-value, ist es sowieso egal. Für referenzbasierte Elemente (zB über Zeiger) ist derjenige verantwortlich, der die Elemente in den Container einfügt. Wann also löschen? Dafür gibt es verschiedene Möglichkeiten. ZB kannst du solche Elemente wiederum selbst in Container packen. Siehe dazu Smart Pointer. Oder du löschst die Elemente, wenn du deinen Baum löschst. Nur mach das unanhängig davon, also nicht in deiner Baum-Klasse. Dann kommst du erst gar nicht in Situationen solch seltsame Sachen, wie in deinem Fall Lebensdauerunterscheidungen, umsetzen zu wollen. Alles eine Frage des Designs, was aber letztendlich auch bedeutet, dass du mehr Gehirnschmalz brauchst. Und dazu kannst du ruhig auch mal über den Tellerrand schauen und nicht stupide das nachmachen, was man in vielen Tutorials zu Gesicht bekommt. Sachen wie

    int* my_array = new int[10];
    //...
    delete my_array;
    

    sind Speicherreservierung und -freigabe unterster Schublade, verleiten zu Fehlern (wie im Beispiel) und sind in C++ nur äusserst selten notwendig. Da gibt es schönere Alternativen ohne gleich einen GC implementieren zu wollen. Das was du vorhast, wird vermutlich 'eh nicht funktionieren. Oder es wird kein richtiger GC. Darüber wurde hier in den letzten Monaten schon so einiges diskutiert. Ich habe zwar nicht alles mitbekommen, aber es gibt wohl einige Probleme, einen vernünftigen GC für C++ zu implementieren.



  • Barnski schrieb:

    CStoll schrieb:

    Wieso willst du die Adresse überhaupt in einen int reinpacken? Pointer-Datentypen kann man doch genausogut direkt verrechnen und zwischen seinen Funktionen übergeben.

    Meine Linked list die ich gemacht habe, hat für jedes Element einen Key vom Typ int, anhand dessen die elemente sortiert werden können (man kann ja auf elemente keinen < operator definieren, weil das item nich unbedingt ne Klasse sein muss...). Ich möchte die Pointer also nach ihrer Adresse im Memory sortieren, bzw danach suchen.

    Du kannst afaik auch < auf Pointer anwenden (und ansonsten kannst du auch vom übergebenen Typ fordern, daß er einen <-Operator (oder eine Vergleichsfunktion) bereitstellt, wenn er die sort()-Funktion nutzen will - so macht es zumindest die STL).


Anmelden zum Antworten