Frage

Gibt es eine Möglichkeit, um portably die oberen zu bestimmen und auf hohlraumZeigerWerte in ANSI C89 / ISO C90 unteren Grenze? (I zur Zeit nicht bei mir eine Kopie des Standard hat (ich habe . ein zu Hause) natürlich, wenn hohlraumZeigerWerte um diese Aufgabe werden garantiert nicht signiert ist trivial (via sizeof (void *).), aber ich mich nicht erinnern kann, wenn dies oder nicht garantiert ich denke an ein paar sehr ineffizient Algorithmen (Schritt bis Überlauf, etc.), aber ich würde gerne wissen, ob jemand eine relativ billig (in Bezug auf die Zeit-Komplexität) und tragbare Art und Weise, diese Grenzen zu berechnen hat.)

- EDIT -

auch: Gibt es eine tragbare Art und Weise die Gültigkeit der Zeigerwerte

zu bestimmen?

Warum: Das kam in einem Gespräch mit einem Kollegen und es verblüfft mich. Ich weiß nicht, was er arbeitet, aber ich möchte nur wissen, weil ich interessiert bin! : -)

War es hilfreich?

Lösung

Es gibt keine tragbare Art und Weise zu bestimmen, ob ein gegebener Zeiger gültig ist oder nicht. Sie müssen wissen, welche Art von Speichersystem Sie es zu tun. Je nach Betriebssystem und Prozessor, kann es oder auch nicht ein Weg sein, die virtuellen Speicher-Manager Seite Tabellen abfragen, um die gültigen Bereiche von Zeigern zu bestimmen.

Zum Beispiel auf Linux können Sie die spezielle mmap Datei unter /proc untersuchen die virtuelle Speicherkarte eines Prozesses zu bekommen. Hier ist ein Beispiel von cat seine eigenen Speicher Karte Auslesen:

$ cat /proc/self/mmap
08048000-0804c000 r-xp 00000000 09:00 5128276                            /bin/cat
0804c000-0804d000 rw-p 00003000 09:00 5128276                            /bin/cat
0804d000-0806e000 rw-p 0804d000 00:00 0                                  [heap]
f7ca7000-f7e40000 r--p 00000000 09:00 3409654                            /usr/lib/locale/locale-archive
f7e40000-f7e41000 rw-p f7e40000 00:00 0 
f7e41000-f7f68000 r-xp 00000000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f68000-f7f6d000 r--p 00127000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f6d000-f7f6f000 rw-p 0012c000 09:00 2654292                            /lib/tls/i686/cmov/libc-2.3.6.so
f7f6f000-f7f72000 rw-p f7f6f000 00:00 0 
f7f83000-f7f85000 rw-p f7f83000 00:00 0 
f7f85000-f7f9a000 r-xp 00000000 09:00 2637871                            /lib/ld-2.3.6.so
f7f9a000-f7f9c000 rw-p 00014000 09:00 2637871                            /lib/ld-2.3.6.so
ff821000-ff836000 rw-p 7ffffffea000 00:00 0                              [stack]
ffffe000-fffff000 r-xp ffffe000 00:00 0                                  [vdso]

Sie können die Bereiche gültiger Zeiger sehen, zusammen mit den Bits angibt, ob der Speicher (r) eadable, (w) ritable, e (x) ecutable oder (p) erneut gesendet (dh nicht auf der Festplatte ausgelagert) .

Andere Tipps

Pointers werden durch spec garantiert ohne Vorzeichen zu sein. Aber warum auf der Erde zu tun, um die Grenzen finden wollen? „Alles, was zwischen 0x00000001 und 0xffffffff“ ist nicht wirklich ein nützlicher Test, da die Anzahl der gültig Zeiger werden einige kleine Teilmengen davon sein.

void * ist immer groß genug, um einen Zeiger auf Speicher zu halten. Jede andere Verwendung ist von der Major League Baseball-Vereinigung streng verboten.

Beispiel: Die dec-10 eine 36-Bit-Architektur mit 36-Bit-Worten war. Doch die Adressen waren 18 Bits und man kann zwei Zeiger in jedem Register / Wort halten.

Ja - das ist ein extremes Beispiel. Wenn Sie mit Zeigern tun Mathe muss, sizeof gültig ist; aber auf etwas anderes als eine zusammenhängende Anordnung Zeiger Mathematik zu tun ist dodgier als vertrackt.

Endlich - niemals einen ‚void *‘ verwenden, um einen Zeiger auf ein Objekt oder Zeiger auf ein Element in C ++ zu speichern. Viele Compiler-Implementierung verwenden tatsächlich mehrere ‚physischen‘ Zeiger mehrere inheritence aus Beton (oder teilweise aus Beton) Klassen zu implementieren. In Wirklichkeit das kommt so gut wie nie, weil nur sehr wenige Menschen die Mehrfachvererbung auf diese Weise verwenden, und wenn sie es tun, sehr selten in Scheiben schneiden und unslice Zeiger. Wenn es nicht kommen, es ist wirklich schwer, herauszufinden, was passiert ist.

Sie haben den Integer-Wert zu erkennen, an dem ein void * von dem tatsächlichen Bitmuster im Speicher gegossen werden kann - eine void * auf einen ganzzahligen Typen Gießen können Umwandlungen beinhalten

Unter der Annahme, sizeof(void *) == sizeof(long) für ein void * p Folgendes kann gut sein, falsch:

((long)p) == *((long *)&p)

Auch dann, wenn der Standard nicht festgelegt, ob es auch ist ein ganze Zahl Typ, der groß genug, um die Werte aller gültigen Zeiger zu halten!

Daher gibt es einfach keine tragbare Art und Weise zu tun, was Sie ...

tun wollen

Abgesehen von einem Bereich, der auf NULL entspricht, gibt es keine (portable) Einschränkung auf den Speicheradressen überhaupt. Ein ausreichend gehärtetes O verschiedene CPU / OS-Mechanismen verwenden, könnte jeden Prozess mit zufälligen und gut verteilen Adressen mit jedem Aufruf von malloc (), und der Position unabhängig ausführbaren zuzüglich ASLR zu liefern Code erlaubt auch von einem beliebigen Adresse auszuführen.

Ich weiß, dass auf Win32, 64-Bit-Zeiger sind Vorzeichen erweiterten. Es macht Spaß, einen 32-Bit minidump von einem 64-Bit-Rechner zu inspizieren, wenn Sie nicht unterzeichnen Zeiger verlängern.

Siehe hier , wie ein 64 -Bit-Zeiger (POINTER_64) funktioniert auf Win32.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top